Socket
Socket
Sign inDemoInstall

@wixc3/common

Package Overview
Dependencies
Maintainers
85
Versions
56
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@wixc3/common - npm Package Compare versions

Comparing version 2.2.1 to 3.0.0

dist/cjs/chain.d.ts

12

package.json
{
"name": "@wixc3/common",
"version": "2.2.1",
"version": "3.0.0",
"description": "Common utils, usable in all environments",
"main": "dist/index.js",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"author": "Wix.com",

@@ -11,4 +12,4 @@ "sideEffects": false,

"src",
"test",
"!dist/tsconfig.tsbuildinfo"
"!dist/*/test",
"!dist/*/tsconfig.tsbuildinfo"
],

@@ -23,3 +24,6 @@ "license": "MIT",

"@file-services/types": "^7.0.1"
},
"devDependencies": {
"@microsoft/api-documenter": "^7.19.22"
}
}

@@ -1,86 +0,165 @@

import { at, concat, every, filter, find, first, Flat, flat, flatMap, forEach, includes, isEmpty, last, map, Mapping, next, Predicate, prev, reduce, size, some, unique } from "./iterables"
import { mapValue } from "./objects"
import {
at,
concat,
every,
filter,
find,
first,
Flat,
flat,
flatMap,
forEach,
includes,
isEmpty,
join,
last,
map,
Mapping,
next,
Predicate,
prev,
reduce,
size,
skip,
some,
sort,
unique,
} from './iterables';
import { mapValues } from './objects';
/**
* {@label Iter}
* Chain iterable operations, each acting on the output of the previous step
*
* @example <caption>When the action is per item, the result is accessible as *iterable*</caption>
* @example When the action is per item, the result is accessible as *iterable*
* ```
* chain([0,1,2])
* .filter(i => i)
* .map(i => i**2)
* .iterable => [1,4]
* @example <caption>When the action returns an element (as in first, next, reduce etc) the the result is accessible as *value*</caption>
* chain([0,1,2]).filter(i => i).first().value => 1
* @example <caption>However, iterable is always accessible, as a single element iterable</caption>
* chain([0,1,2]).filter(i => i).first().iterable => [1]
* @example <caption>**Note** if the action returned undefined, iterable will be empty </caption>
* chain([]).first().iterable => []
* chain([]).first().value => undefined
* @param value
* @returns
* .iterable
* // => [1,4]
* ```
* @example When the action returns an element (as in first, next, reduce etc) the the result is accessible as *value*
* ```
* chain([0,1,2]).filter(i => i).first().value
* // => 1
* ```
* @example Iterable is always accessible, as a single element iterable
* ```
* chain([0,1,2]).filter(i => i).first().iterable
* // => [1]
* ```
* @example <b>Note</b> if the action returned undefined, iterable will be empty
* ```
* chain([]).first().iterable // => []
* chain([]).first().value // => undefined
* ```
* @param value - initial iterable
* @returns Chainable action on iterable
*/
export function chain<T>(iterable: Iterable<T>): IterableChain<T>
export function chain<T, V extends NotIterable<T>>(value: V): ValueChain<V>
export function chain<T>(value: Iterable<T>): IterableChain<T>;
/**
* {@label Iter}
* Chain iterable operations, each acting on the output of the previous step
* @example When the action is per item, the result is accessible as *iterable*
* ```
* chain([0,1,2])
* .filter(i => i)
* .map(i => i**2)
* .iterable
* // => [1,4]
* ```
* @example When the action returns an element (as in first, next, reduce etc) the the result is accessible as *value*
* ```
* chain("hello").map(i => i.split("")).first().value
* // => "h"
* ```
* @example Iterable is always accessible, as a single element iterable
* ```
* chain([0,1,2]).filter(i => i).first().iterable
* // => [1]
* ```
* @example <b>Note</b> if the action returned undefined, iterable will be empty
* ```
* chain([]).first().iterable // => []
* chain([]).first().value // => undefined
* ```
* @param value - initial value
* @returns Chainable action on iterable
*/
export function chain<T, V extends NotIterable<T>>(value: V): ValueChain<V>;
export function chain<T>(value: T) {
const iterable = (value === undefined
? []
: value === null
? [null]
: Symbol.iterator in value
? value
: [value]) as Iter<T>
const iterable = (
value === undefined ? [] : value === null ? [null] : Symbol.iterator in value ? value : [value]
) as Iter<T>;
return iterable === value
? chainIter(iterable)
: chainElement(value)
return iterable === value ? chainIter(iterable) : chainElement(value);
}
function chainIter<T>(iterable: Iterable<T>): IterableChain<T> {
const toIter = { map, flatMap, filter, concat, flat, unique }
const toElm = { last, first, isEmpty, size, at, next, prev, find, some, includes, every, reduce }
const toIter = { skip, map, flatMap, filter, concat, flat, unique, sort } as const;
const toElm = { join, last, first, isEmpty, size, at, next, prev, find, some, includes, every, reduce } as const;
const boundToIter = mapValues(
toIter,
(v) =>
(...args: unknown[]) =>
chainIter(
(v as (iterable: Iterable<unknown>, ...args: unknown[]) => Iterable<unknown>)(iterable, ...args)
)
);
const boundToElm = mapValues(
toElm,
(v) =>
(...args: unknown[]) =>
chainElement((v as (iterable: Iterable<unknown>, ...args: unknown[]) => unknown)(iterable, ...args))
);
return {
value: iterable,
iterable,
...mapValue(toIter, v => (...args: any[]) => chainIter(v(iterable, ...args) as Iterable<unknown>)),
...mapValue(toElm, v => (...args: any[]) => chainElement(v(iterable, ...args) as Iterable<unknown>)),
...boundToIter,
...boundToElm,
forEach: (mapping: Mapping<T, unknown>) => {
forEach(iterable, mapping)
return chainIter(iterable)
}
} as any as IterableChain<T>
forEach(iterable, mapping);
return chainIter(iterable);
},
} as IterableChain<T>;
}
function chainElement<T>(value: T): ValueChain<T> {
const iterable = (value === undefined ? [] : [value]) as Iterable<T>
const iterable = (value === undefined ? [] : [value]) as Iterable<T>;
return {
...chainIter(iterable),
value
}
value,
};
}
type IterableChain<T> = Chain<T> & {value:Iterable<T>}
type ValueChain<T> = Chain<T> & {value:T}
type NotIterable<T> = T extends Iterable<unknown> ? never : T
type Iter<T> = T extends Iterable<infer E> ? Iterable<E> : Iterable<T>
type Chain<T> = {
last: () => ValueChain<T>
first: () => ValueChain<T>
isEmpty: () => ValueChain<boolean>
size: () => ValueChain<number>
at: (index: number) => ValueChain<T>
next: () => ValueChain<T>
prev: () => ValueChain<T>
unique: () => IterableChain<T>
map: <S>(m: Mapping<T, S>) => IterableChain<S>
flatMap: <S>(m: Mapping<T, S>) => IterableChain<Flat<S>>
filter: (p: Predicate<T>) => IterableChain<T>
concat: (...iterables: Iterable<T>[]) => IterableChain<T>
forEach: (fn: Mapping<T, unknown>) => IterableChain<T>
find: (p: Predicate<T>) => ValueChain<T>
includes: (element: T) => ValueChain<boolean>
some: (p: Predicate<T>) => ValueChain<boolean>
every: (p: Predicate<T>) => ValueChain<boolean>
flat: () => IterableChain<Flat<T>>
reduce: <A>(reducer:(acc:A, item:T)=>A, initial:A) => ValueChain<A>
iterable: Iterable<T>
}
export type IterableChain<T> = Chain<T> & { value: Iterable<T> };
export type ValueChain<T> = Chain<T> & { value: T };
export type NotIterable<T> = T extends Iterable<unknown> ? never : T;
export type Iter<T> = T extends Iterable<infer E> ? Iterable<E> : Iterable<T>;
export type Chain<T> = {
last: () => ValueChain<T>;
first: () => ValueChain<T>;
isEmpty: () => ValueChain<boolean>;
size: () => ValueChain<number>;
at: (index: number) => ValueChain<T>;
next: () => ValueChain<T>;
prev: () => ValueChain<T>;
unique: () => IterableChain<T>;
map: <S>(m: Mapping<T, S>) => IterableChain<S>;
flatMap: <S>(m: Mapping<T, S>) => IterableChain<Flat<S>>;
filter: (p: Predicate<T>) => IterableChain<T>;
concat: (...iterables: Iterable<T>[]) => IterableChain<T>;
forEach: (fn: Mapping<T, unknown>) => IterableChain<T>;
find: (p: Predicate<T>) => ValueChain<T>;
includes: (element: T) => ValueChain<boolean>;
some: (p: Predicate<T>) => ValueChain<boolean>;
sort: (p: Predicate<T, number>) => IterableChain<T>;
every: (p: Predicate<T>) => ValueChain<boolean>;
flat: () => IterableChain<Flat<T>>;
join: () => ValueChain<string>;
skip: (count: number) => IterableChain<T>
reduce: <A>(reducer: (acc: A, item: T) => A, initial: A) => ValueChain<A>;
iterable: Iterable<T>;
};

@@ -12,3 +12,3 @@ export type PromiseResolveCb<T> = (value: T | PromiseLike<T>) => void;

* A closure-less alternative to new Promise(...)
* @returns
* @returns
*/

@@ -15,0 +15,0 @@ export function deferred<T = void>(): IDeferredPromise<T> {

@@ -8,3 +8,3 @@ export function enumValues<T extends string>(enumObj: { [key: string]: T }): IterableIterator<T>;

// TODO: validate
export function* enumValues<T>(enumObj: Record<string,T>): IterableIterator<T> {
export function* enumValues<T>(enumObj: Record<string, T>): IterableIterator<T> {
let isStringEnum = true;

@@ -11,0 +11,0 @@ for (const property in enumObj) {

@@ -7,4 +7,5 @@ import { isPlainObject } from './objects';

*/
export const toError = (value: unknown): Error =>
value instanceof Error ? value : new Error(value === undefined ? undefined : String(value));
export function toError(value: unknown): Error {
return value instanceof Error ? value : new Error(value === undefined ? undefined : String(value));
}

@@ -14,6 +15,8 @@ /**

*/
export const getErrorCode = (error: Error & { code?: string }): string | undefined => {
export function getErrorCode(error: Error & { code?: string }): string | undefined {
return typeof error.code === 'string' ? error.code : undefined;
};
}
/**
*/
export class ErrorWithCode extends Error {

@@ -23,3 +26,3 @@ public code?: string;

public constructor(message?: string, options?: { code?: string; cause?: unknown }) {
const { code, ...nativeErrorOptions } = options ?? {};
const { code, ...nativeErrorOptions } = options ?? {};
super(message, nativeErrorOptions);

@@ -33,2 +36,3 @@ this.code = code;

* @example
* ```ts
* declare const align: 'left' | 'right' | 'middle';

@@ -41,2 +45,3 @@ * switch (align) {

* }
* ```
*/

@@ -70,5 +75,7 @@ export class UnreachableCaseError extends Error {

export function isErrorLikeObject(error: unknown): error is Error {
return isPlainObject(error)
&& typeof (error as {name?:string}).name === 'string'
&& typeof (error as {message?:string}).message === 'string';
return (
isPlainObject(error) &&
typeof (error as { name?: string }).name === 'string' &&
typeof (error as { message?: string }).message === 'string'
);
}

@@ -0,19 +1,25 @@

/**
* @returns a no operation function
*/
export const noop = () => undefined;
/**
* @returns a function that returns a resolved Promise
*/
export const asyncNoop = () => Promise.resolve();
/**
*
* @param fn
* Make a function executable only once, following calls are ignored
* @returns fn, wrapped to run only upon first execution
*/
export const once = <T extends (...args:unknown[])=>unknown>(fn:T):T => {
export function once<T extends (...args: any[]) => any>(fn: T): T {
let run = false;
let result:ReturnType<T>;
return ((...args:unknown[]) => {
let result: ReturnType<T>;
return ((...args: unknown[]) => {
if (!run) {
run = true;
result = fn(...args) as ReturnType<T>
result = fn(...args) as ReturnType<T>;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return result;
}) as T
}) as T;
}

@@ -1,20 +0,18 @@

export * from './strings'
export * from './numbers'
export * from './objects'
export * from './iterables'
export * from './chain'
export * from './same'
export * from './errors'
export * from './sets'
export * from './debouncer'
export * from './enum-values'
export * from './index'
export * from './lru-cache'
export * from './platform'
export * from './signal'
export * from './functions'
export * from './deferred'
export * from './set-multi-map'
export * from './event-emitter'
export * from './types'
export * from './maps'
/**
* @packageDocumentation
* Useful utils for strings, iterables, objects, maps, promises and other commonly used structures
*/
export * from './strings';
export * from './numbers';
export * from './objects';
export * from './iterables';
export * from './chain';
export * from './same';
export * from './errors';
export * from './sets';
export * from './enum-values';
export * from './index';
export * from './platform';
export * from './functions';
export * from './types';
export * from './maps';

@@ -1,16 +0,16 @@

import { isDefined, Nullable } from "./types"
import { isDefined, Nullable } from './types';
export type Mapping<S, T> = (src: S) => T
export type Predicate<S, V = boolean> = (src: S) => V
export type Flat<T> = T extends Iterable<infer A> ? A : T
export type Mapping<S, T> = (src: S) => T;
export type Predicate<S, V = boolean> = (src: S) => V;
export type Flat<T> = T extends Iterable<infer A> ? A : T;
/**
* @param iterable
* @returns the last element of iterable
* Picks the last element of an iterable
* @returns undefined for null/empty iterable
*/
export function last<T>(iterable: Nullable<Iterable<T>>): T | undefined {
let last!: T
let last!: T;
if (iterable) {
for (const value of iterable) {
last = value
last = value;
}

@@ -22,36 +22,37 @@ }

/**
* @param iterable
* @returns the first element of iterable
* Picks the first element of an iterable
* @returns undefined for null/empty iterable
*/
export const first = <T>(iterable: Nullable<Iterable<T>>): T | undefined =>
at(iterable, 0)
export function first<T>(iterable: Nullable<Iterable<T>>): T | undefined {
return at(iterable, 0);
}
/**
* @param iterable
* @returns the first element of iterable
* Checks if an iterable is empty
*/
export function isEmpty(iterable: Iterable<unknown>): boolean {
for (const _ of iterable) {
return false
return false;
}
return true
return true;
}
/**
* @param iterable
* @returns the elements count of iterable
* Evaluate the size of an iterable
* @returns elements count of iterable, 0 if null
*/
export function size(iterable: Iterable<unknown>): number {
let size = 0
for (const _ of iterable) {
size++;
export function size(iterable: Nullable<Iterable<unknown>>): number {
let size = 0;
if (iterable) {
for (const _ of iterable) {
size++;
}
}
return size
return size;
}
/**
* Finds element by index, including negative index
* @see Array.at
* @param iterable
* @param index
* @returns the element at the given index
* @returns undefined if invalid index or null iterable
*/

@@ -61,3 +62,3 @@ export function at<T>(iterable: Nullable<Iterable<T>>, index: number): T | undefined {

if (index < 0) {
return Array.from(iterable).at(index)
return Array.from(iterable).at(index);
}

@@ -67,62 +68,59 @@ let i = 0;

if (i++ === index) {
return v
return v;
}
}
}
return undefined
return undefined;
}
/**
* @param iterable
* @param item
* @returns the element after item, undefined if last or not found
* Find the element following an item
* @returns undefined if item is last or not found
*/
export function next<T>(iterable: Nullable<Iterable<T>>, item: T): T | undefined {
let wasFound = false
let wasFound = false;
if (iterable) {
for (const v of iterable) {
if (wasFound) {
return v
return v;
}
if (v === item) {
wasFound = true
wasFound = true;
}
}
}
return undefined
return undefined;
}
/**
* @param iterable
* @param item
* @returns the elements before item, undefined if first or not found
* Find the element before an item
* @returns undefined if item is first or not found
*/
export function prev<T>(iterable: Nullable<Iterable<T>>, item: T): T | undefined {
let prev!: T
let prev!: T;
if (iterable) {
for (const v of iterable) {
if (v === item) {
return prev
return prev;
}
prev = v
prev = v;
}
}
return undefined
return undefined;
}
/**
* @param iterable
* @param by an element identifier function
* @returns an iterable with unique elements
* Creates iterable of unique elements
* @param by - an element identifier (hash) function
*/
export function* unique<T>(iterable: Nullable<Iterable<T>>, by: Predicate<T, unknown> = i => i): Iterable<T> {
const known = new Set<unknown>()
export function* unique<T>(iterable: Nullable<Iterable<T>>, by: Predicate<T, unknown> = (i) => i): Iterable<T> {
const known = new Set<unknown>();
if (iterable) {
for (const v of iterable) {
if (!known.has(by(v))) {
known.add(by(v))
known.add(by(v));
yield v;
}
}
known.clear()
known.clear();
}

@@ -132,6 +130,4 @@ }

/**
* Map iterable elements
* @see Array.map
* @param iterable
* @param mapFn
* @returns a mapped iterable
*/

@@ -141,3 +137,3 @@ export function* map<S, T>(iterable: Nullable<Iterable<S>>, mapFn: Mapping<S, T>): Iterable<T> {

for (const v of iterable) {
yield mapFn(v)
yield mapFn(v);
}

@@ -149,8 +145,6 @@ }

* @see Array.flatMap
* @param iterable
* @param mapFn
* @returns a mapped, flattened iterables
*/
export function* flatMap<S, T>(iterable: Nullable<Iterable<S>>, mapFn: Mapping<S, T | Iterable<T>>): Iterable<Flat<T>> {
yield* flat(map(iterable, mapFn))
yield* flat(map(iterable, mapFn));
}

@@ -160,5 +154,2 @@

* @see Array.filter
* @param iterable
* @param predicate
* @returns a filtered iterable
*/

@@ -169,3 +160,3 @@ export function* filter<T>(iterable: Nullable<Iterable<T>>, predicate: Predicate<T>): Iterable<T> {

if (predicate(v)) {
yield v
yield v;
}

@@ -178,3 +169,2 @@ }

* @see Array.concat
* @param iterables
* @returns a concatenated iterable

@@ -192,4 +182,2 @@ */

* @see Array.forEach
* @param iterable
* @param fn
*/

@@ -199,3 +187,4 @@ export function forEach<T>(iterable: Nullable<Iterable<T>>, fn: Mapping<T, unknown>): void {

for (const v of iterable) {
fn(v)
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
fn(v);
}

@@ -207,4 +196,2 @@ }

* @see Array.find
* @param iterable
* @param predicate
* @returns the first element the satisfies the predicate

@@ -216,7 +203,7 @@ */

if (predicate(v)) {
return v
return v;
}
}
}
return undefined
return undefined;
}

@@ -226,8 +213,6 @@

* @see Array.includes
* @param iterable
* @param item
* @returns item is an element of iterable
*/
export function includes<T>(iterable: Nullable<Iterable<T>>, item: T): boolean {
return !!find(iterable, i => i === item)
return !!find(iterable, (i) => i === item);
}

@@ -237,8 +222,6 @@

* @see Array.some
* @param iterable
* @param predicate
* @returns there is an element satisfies the predicate
*/
export function some<T>(iterable: Nullable<Iterable<T>>, predicate: Predicate<T>): boolean {
return !!find(iterable, predicate)
return !!find(iterable, predicate);
}

@@ -248,4 +231,2 @@

* @see Array.every
* @param iterable
* @param predicate
* @returns true is all elements satisfy the predicate

@@ -256,6 +237,6 @@ */

if (!predicate(v)) {
return false
return false;
}
}
return true
return true;
}

@@ -265,5 +246,4 @@

* @see Array.flat
* @param deep if true, repeat the flattening until all elements are not iterable
* @param iterable
* @returns a flattened iterable,
* @param deep - if true, repeat the flattening until all elements are not iterable
* @returns a flattened iterable,
* where elements that are iterable are spread into the result

@@ -276,3 +256,3 @@ */

// @ts-expect-error v is definitely iterable
yield* (deep ? flat(v) : v)
yield* deep ? flat(v) : v;
} else {

@@ -286,12 +266,11 @@ yield v as Flat<T>;

/**
*
* @param iterable
* @returns an histogram map (element=>count)
* Calculate a histogram of iterable elements
* @returns an histogram map (element=\>count)
*/
export function histogram<T>(iterable: Iterable<T>) {
const histogram = new Map<T, number>()
forEach(iterable, i => {
const count = histogram.get(i) || 0
histogram.set(i, count + 1)
})
const histogram = new Map<T, number>();
forEach(iterable, (i) => {
const count = histogram.get(i) || 0;
histogram.set(i, count + 1);
});
return histogram;

@@ -301,19 +280,14 @@ }

/**
*
* @param x
* @returns true if x is iterable
*/
export function isIterable(x: any): x is Iterable<unknown> {
return isDefined(x) && typeof x === 'object' && (Symbol.iterator in x)
return isDefined(x) && typeof x === 'object' && Symbol.iterator in x;
}
/**
* @see Array.sort
* @param iterable
* @param by comparator
* @see Array<T>.sort
* @param by - comparator, returns a negative value if a should precede b
*/
export function sort<T>(iterable: Nullable<Iterable<T>>, by?: (a: T, b: T) => number): Iterable<T> {
return iterable
? [...iterable].sort(by)
: []
return iterable ? [...iterable].sort(by) : [];
}

@@ -323,5 +297,2 @@

* @see Array.reduce
* @param iterable
* @param reducer
* @param initial
* @returns reduced object

@@ -333,3 +304,3 @@ */

for (const item of iterable) {
acc = reducer(acc, item)
acc = reducer(acc, item);
}

@@ -340,14 +311,58 @@ }

/**
* @see Array.join
*/
export function join<T extends string>(iterable: Nullable<Iterable<T>>, separator: string): string {
if (!iterable) {
return '';
}
let result = first(iterable) || '';
let prev: string | null = null;
for (const v of skip(iterable, 1)) {
if (prev) {
result = result + separator + prev;
}
prev = v;
}
if (prev) {
result = result + separator + prev;
}
return result;
}
export const groupBy = <T, K extends keyof T>(elements: Iterable<T>, property: K): Map<T[K], T[]> =>
reduce(elements, (acc, element) => {
const propertyValue = acc.get(element[property]);
if (propertyValue) {
propertyValue.push(element);
} else {
acc.set(element[property], [element]);
/**
* Skips the first elements of an iterable
*/
export function* skip<T>(iterable: Nullable<Iterable<T>>, count: number): Iterable<T> {
if (iterable) {
for (const item of iterable) {
if (count === 0) {
yield item;
} else {
count--;
}
}
}
}
return acc;
}, new Map<T[K], T[]>());
/**
* Groups elements by the value of a property
* @returns A map of the value to an array of elements
*/
export function groupBy<T, K extends keyof T>(elements: Iterable<T>, property: K): Map<T[K], T[]> {
return reduce(
elements,
(acc, element) => {
const propertyValue = acc.get(element[property]);
if (propertyValue) {
propertyValue.push(element);
} else {
acc.set(element[property], [element]);
}
return acc;
},
new Map<T[K], T[]>()
);
}

@@ -1,2 +0,2 @@

import { isMap, Nullable } from "./types"
import { isMap, Nullable } from './types';

@@ -7,27 +7,26 @@ /**

* @see Map.has
* @param obj
* @param key
* @returns
*/
export function has<O extends object>(obj: O, key: keyof O): boolean;
/**
* Similar to Map.has, but works for plain objects, and returns false
* for null maps
* @see Map.has
*/
export function has<K>(obj: Map<K, unknown>, key: K): boolean;
export function has(obj: null | undefined, key: unknown | never): false;
export function has(obj: Nullable<object | Map<unknown, unknown>>, key: any): boolean {
return !!obj && (
return (
!!obj &&
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
typeof (obj as any).has === 'function'
? (obj as Map<any, any>).has(key)
: key in (obj as object))
(typeof (obj as any).has === 'function' ? (obj as Map<any, any>).has(key) : key in (obj as object))
);
}
type MapValue<T> = T extends Map<infer _, infer V> ? V : never
type ObjValue<O extends object, K extends keyof O = keyof O> = O[K]
export type MapValue<T> = T extends Map<infer _, infer V> ? V : never;
export type ObjValue<O extends object, K extends keyof O = keyof O> = O[K];
/**
* Similar to Map.get, but works for plain objects, and returns undefined
* Similar to Map.get, but works for plain objects, and returns undefined
* for null maps and missing keys
* @see Map.get
* @param obj
* @param key
* @return found value, *undefined* if map/value to not exist
* @returns found value, *undefined* if map/value to not exist
*/

@@ -41,19 +40,14 @@ export function get<O extends object, K extends keyof O>(obj: O, key: K): ObjValue<O, K>;

? (obj as Map<any, any>).get(key)
// @ts-expect-error definitely not a map or nullish
: obj[key as string]
: // @ts-expect-error definitely not a map or nullish
obj[key as string];
}
return
return;
}
/**
* Returns a value by key, throws if the value is missing or the map null
* @param map
* @param key
* @param errorMessage
* @returns
*/
export function getValue<T extends object>(map: T, key: keyof T, errorMessage?: string): ObjValue<T>
export function getValue<K, V, T extends Map<K, V>>(map: T, key: K, errorMessage?: string): MapValue<T>
export function getValue<T extends null | undefined>(map: T, key: unknown | never, errorMessage?: string): never
export function getValue<T extends object>(map: T, key: keyof T, errorMessage?: string): ObjValue<T>;
export function getValue<K, V, T extends Map<K, V>>(map: T, key: K, errorMessage?: string): MapValue<T>;
export function getValue<T extends null | undefined>(map: T, key: unknown | never, errorMessage?: string): never;
export function getValue<T extends Map<K, V> | object, K, V>(map: Nullable<T>, key: KeyOf<T>, errorMessage?: string) {

@@ -63,30 +57,26 @@ // @ts-expect-error hmm

// @ts-expect-error hmmm
return get(map, key)
return get(map, key);
}
throw new Error(errorMessage || `Missing map`)
throw new Error(errorMessage || `Missing map`);
}
type KeyOf<T> = T extends Map<infer K, infer _> ? K :
T extends object ? keyof T : never
type KeyOf<T> = T extends Map<infer K, infer _> ? K : T extends object ? keyof T : never;
/**
* @see Map.keys
* @see Object.keys
* @param map
* @returns an iterable of the map/object keys
*/
export function keys<K, O extends Map<K, any>>(map: O): Iterable<K>
export function keys<O extends object>(map: O): Iterable<keyof O>
export function keys<K, O extends Map<K, any>>(map: O): Iterable<K>;
export function keys<O extends object>(map: O): Iterable<keyof O>;
export function keys<K, O extends object | Map<K, any>>(obj: O) {
return isMap(obj)
? obj.keys()
: Object.keys(obj)
return isMap(obj) ? obj.keys() : Object.keys(obj);
}
export function values<K, O extends Map<K, any>>(map: O): Iterable<MapValue<O>>
export function values<O extends object>(map: O): Iterable<ObjValue<O>>
/**
* @see Map.values
* @see Object.values
*/
export function values<K, O extends Map<K, any>>(map: O): Iterable<MapValue<O>>;
export function values<O extends object>(map: O): Iterable<ObjValue<O>>;
export function values<K, O extends object | Map<K, any>>(obj: O) {
return isMap(obj)
? obj.values()
: Object.values(obj)
return isMap(obj) ? obj.values() : Object.values(obj);
}
import { sleep } from 'promise-assist';
import { chain } from './chain';
import type { UnionToIntersection } from './types';

@@ -16,3 +17,6 @@ export function exclude<R>(...excluded: R[]) {

* returns an object composed of the picked object properties
* @example pick({ a: 1, b: 2 }, ['a']) // => { a: 1 }
* @example
* ```ts
* pick({ a: 1, b: 2 }, ['a']) // => { a: 1 }
* ```
*/

@@ -27,29 +31,48 @@ export function pick<O extends object, K extends keyof O>(record: O, keys: Iterable<K>): Pick<O, K> {

export const mapObject = (obj: object, mapping: (entry: [string, any]) => [string, any]) =>
Object.fromEntries(
Object.entries(obj)
.map(mapping))
/**
* Maps key value pairs of a plain object
*/
export function mapObject(obj: object, mapping: (entry: [string, any]) => [string, any]) {
return Object.fromEntries(Object.entries(obj).map(mapping));
}
/**
* Maps values of a plain object
*/
export function mapValues<T extends object, R>(
obj: T,
mapping: (value: T[keyof T], k?: keyof T) => R
): { [_ in keyof T]: R } {
return Object.fromEntries(
Object.entries(obj).map(([k, v]: [string, T[keyof T]]) => [k, mapping(v, k as keyof T)])
) as { [_ in keyof T]: R };
}
export const mapValue = (obj: object, mapping: (value: any) => any) =>
Object.fromEntries(
Object.entries(obj)
.map(([k, v]) => [k, mapping(v)]))
/**
* Maps values of a plain object
*/
export function mapKeys<T extends object, R extends string>(
obj: object,
mapping: (key: keyof T, value?: T[keyof T]) => R
): Record<R, T[keyof T]> {
return Object.fromEntries(
Object.entries(obj).map(([k, v]: [string, T[keyof T]]) => [mapping(k as keyof T, v), v])
) as Record<R, T[keyof T]>;
}
export const mapKeys = (obj: object, mapping: (key: string) => string) =>
Object.fromEntries(
Object.entries(obj)
.map(([k, v]) => [mapping(k), v]))
/**
* Checks that value is a POJO
*/
export function isPlainObject(value: unknown): value is Record<string | number | symbol, unknown> {
return value !== null && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype;
}
export function isPlainObject(value: unknown): value is Record<string|number|symbol, any>{
return value !== null
&& typeof value === 'object'
&& Object.getPrototypeOf(value) === Object.prototype
/**
* Logs an error
*/
export function reportError(ex: unknown) {
// eslint-disable-next-line no-console, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return
console.error(ex);
}
// eslint-disable-next-line no-console, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return
export const reportError = (ex: unknown) => console.error(ex);
/**

@@ -69,3 +92,3 @@ * Awaits a record of promises, and returns a record of their results.

for (const [key, promise] of Object.entries(obj)) {
out[key] = await promise
out[key] = await promise;
}

@@ -97,7 +120,9 @@ return out as Out;

* First takes on value collisions.
*
* @returns a new object with the values as keys and the keys as values
* @example { a: 'y', b: 'z'} => { y: 'a', z: 'b' }
* @example
* ```ts
* reverseObject({ a: 'y', b: 'z'}) // => { y: 'a', z: 'b' }
* ```
*/
export const reverseObject = (obj: Record<string, string | false | undefined>) => {
export function reverseObject(obj: Record<string, string | false | undefined>) {
const reversedObject: Record<string, string> = {};

@@ -112,46 +137,49 @@

return reversedObject;
};
}
/**
* Returns an object where missing keys and values/keys
* Returns an object where missing keys and values/keys
* that satisfy shouldUseDefault
* to the value in shouldUseDefault.
*
* to the value in shouldUseDefault.
*
* @example
* defaults({}, {a:0}) => {a:0}
* defaults({a:1}, {a:0}) => {a:1}
* defaults({a:{}}, {a:{b:1}}) => {a:{b:1}}
*
* ```ts
* defaults({}, {a:0}) // => {a:0}
* defaults({a:1}, {a:0}) // => {a:1}
* defaults({a:{}}, {a:{b:1}}) // => {a:{b:1}}
* ```
* by default, any undefined value will be replaced
* @param source
* @param defaultValues
* @param deep [true] perform a deep comparison
* @example
* defaults({a:{}}, {a:{b:1}}, false) => {a:{}}
* @param shouldUseDefault [(v,k)=>v===undefined] value/key for which shouldUseDefault returns true will be taken from defaultValues, ignoring source
* k is provided as a dot separated path
* @example
* defaults({a:{b:1}}, {a:{b:2}}, true, (_,k)=>k==='a.b') => {a:{b:2}}
* defaults({a:1}, {a:2}, true, v=>v===1) => {a:2}
* @param deep - [true] perform a deep comparison
* @example
* ```ts
* defaults({a:{}}, {a:{b:1}}, false) // => {a:{}}
* ```
* @param shouldUseDefault - value/key for which shouldUseDefault
* returns true will be taken from defaultValues,
* ignoring source.
* k is provided as a dot separated path
* @example
* ```ts
* defaults({a:{b:1}}, {a:{b:2}}, true, (_,k)=>k==='a.b') // => {a:{b:2}}
* defaults({a:1}, {a:2}, true, v=>v===1) // => {a:2}
* ```
* @returns a new object with merged source and defaultValues
*/
export function defaults<S, D>(_source: S, _defaultValues: D, deep = true, shouldUseDefault = (v: unknown, _key: string) => v === undefined): S & D {
const parseObj = (src: any, dft: any, parentKey = ''): any => {
export function defaults<S extends object, D extends object>(
_source: S,
_defaultValues: D,
deep = true,
shouldUseDefault = (v: unknown, _key: string) => v === undefined
): S & D {
const parseObj = (src: unknown, dft: unknown, parentKey = ''): Record<string, unknown> => {
if (isPlainObject(src)) {
const result = {} as Record<string, any>
const result = {} as Record<string, any>;
for (const [key, value] of Object.entries(src)) {
const fullKey = (parentKey ? parentKey + '.' : '') + key
const _default = isPlainObject(dft)
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
? (dft as any)[key]
: undefined
const fullKey = (parentKey ? parentKey + '.' : '') + key;
const _default = isPlainObject(dft) ? dft[key] : undefined;
if (shouldUseDefault(value, fullKey)) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
result[key] = _default
result[key] = _default;
} else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
result[key] = deep
? parseObj(value, _default, fullKey)
: value
result[key] = deep ? parseObj(value, _default, fullKey) : value;
}

@@ -162,7 +190,8 @@ }

if (!(key in src)) {
result[key] = _default
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
result[key] = _default;
}
}
}
return result
return result;
} else {

@@ -172,13 +201,14 @@ // @ts-expect-error non object values should only affect type when misused

}
}
return parseObj(_source, _defaultValues) as S & D
};
return parseObj(_source, _defaultValues) as S & D;
}
/**
* @param obj The object to query
* @param path The path of the property to get.
* @param obj - The object to query
* @param path - The path of the property to get.
* @returns The value at `path` of `object` id exists, `undefined` otherwise
* @example
* getIn({ a: { b: 'c' } }, ['a', 'b'])
* // => c
* ```ts
* getIn({ a: { b: 'c' } }, ['a', 'b']) // => c
* ```
*/

@@ -190,38 +220,37 @@ export function getIn(obj: Record<string, any>, path: string[]): unknown {

const DELETE = Symbol()
type Remap<T> = Partial<Record<keyof T, string | typeof DELETE>>
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
type Remapped<T extends object, R> =
UnionToIntersection<
R extends Partial<Record<keyof T, string | typeof DELETE>>
? { [K in keyof T]: K extends keyof R
? R[K] extends string
? { [L in R[K]]: T[K] }
: never
: { [L in K]: T[L] }
}[keyof T]
: never>
const DELETE = Symbol();
export type Remap<T> = Partial<Record<keyof T, string | typeof DELETE>>;
export type Remapped<T extends object, R> = UnionToIntersection<
R extends Partial<Record<keyof T, string | typeof DELETE>>
? {
[K in keyof T]: K extends keyof R
? R[K] extends string
? { [L in R[K]]: T[K] }
: never
: { [L in K]: T[L] };
}[keyof T]
: never
>;
type Remapp = {
<T extends object, R extends Remap<T>>(obj: T, rename: R): Remapped<T, R>
readonly DELETE: typeof DELETE
}
export type RemapFunc = {
<T extends object, R extends Remap<T>>(obj: T, rename: R): Remapped<T, R>;
readonly DELETE: typeof DELETE;
};
/**
* remaps keys of obj based on rename map object,
* @param obj
* @param rename key:key name in obj, value: new name (string) OR remap.DELETE
* @returns
* remaps keys of obj based on rename map object,
* @param rename - key:key name in obj, value: new name (string) OR remap.DELETE
* @returns
*/
export const remap:Remapp = <T extends object, R extends Remap<T>>(obj: T, rename: R): Remapped<T, R> => Object.fromEntries(
export const remap: RemapFunc = <T extends object, R extends Remap<T>>(obj: T, rename: R): Remapped<T, R> =>
Object.fromEntries(
chain(Object.entries(obj))
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
.filter(([key]) => (rename as any)[key] !== remap.DELETE)
.map(([key, value]) =>
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
[(rename as any)[key] || key, value] as [string, any])
.iterable
) as Remapped<T, R>
.map(
([key, value]) =>
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
[(rename as any)[key] || key, value] as [string, any]
).iterable
) as Remapped<T, R>;
// @ts-expect-error setting the DELETE const
remap.DELETE = DELETE
remap.DELETE = DELETE;

@@ -1,8 +0,7 @@

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
const _process:{type?:string, platform?:string} = (globalThis as any)['process'];
const _process: { type?: string; platform?: string } = (globalThis as any)['process'];
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
const _navigator:{platform:string} = (globalThis as any)['navigator'];
const _navigator: { platform: string } = (globalThis as any)['navigator'];
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
const platform:string|undefined = _process?.platform;
const platform: string | undefined = _process?.platform;

@@ -9,0 +8,0 @@ export const isMac = platform ? platform === 'darwin' : _navigator?.platform.includes('Mac');

@@ -1,51 +0,63 @@

import { histogram, isIterable, size } from "./iterables"
import { isPlainObject } from "./objects"
import { isMap, isSet } from "./types"
import { histogram, isIterable, size } from './iterables';
import { isPlainObject } from './objects';
import { isMap, isSet } from './types';
/**
* deep comparison of two items
* Deep comparison of two objects
* @example
* ```ts
* same({a:1, b:2},{b:2, a:1}) // => true
* same(new Map([['a',1],['b',2]]), new Map([['b',2],['a',1]])) // => true
* same(new Map([[{a:1},{b:1}]]]), new Map([[{a:1},{b:1}]]])) // => true
* same([0,1], [1,0]) // => false
* same([0,1], [1,0], true) // => true
* ```
* @remarks
* items are "the same" if:
*
* - a === b (for anything other than iterables & POJO)
* - a and b are POJO with same entries (order ignored, *same* used to compare values)
* - a and b are Maps with same entries (order ignored, *same* used to compare keys & values)
* - a and b are Sets with same values (order ignored, *same* used to compare values)
* - a and b are POJO with same entries (order ignored, {@link same} used to compare values)
*
* - a and b are Maps with same entries (order ignored, {@link same} used to compare keys & values)
*
* - a and b are Sets with same values (order ignored, {@link same} used to compare values)
*
* - a and b are iterable (that are not Set or Map) with the same values, order checked if unordered=false (default)
* @param a
* @param b
* @param unordered [false] Note: relevant only in array like iterables. objects, sets and maps are *never checked for order* of entries
* @returns
*
* @param unordered - [false] Note: relevant only in array like iterables. objects, sets and maps are *never checked for order* of entries
*/
export function same<T>(a: T, b: T, unordered = false): boolean {
if (a === b) return true
if (a === b) return true;
if (!isIterable(a) || !isIterable(b)) {
if (isPlainObject(a) && isPlainObject(b)) {
return sameIgnoreOrder(Object.entries(a), Object.entries(b), unordered)
return sameIgnoreOrder(Object.entries(a), Object.entries(b), unordered);
}
return a === b
return a === b;
}
return unordered ||
(isMap(a) && isMap(b)) ||
(isSet(a) && isSet(b))
? sameIgnoreOrder(a, b, unordered) : sameInOrder(a, b, unordered)
return unordered || (isMap(a) && isMap(b)) || (isSet(a) && isSet(b))
? sameIgnoreOrder(a, b, unordered)
: sameInOrder(a, b, unordered);
}
function sameInOrder<T>(a: T, b: T, unordered:boolean) {
function sameInOrder<T>(a: T, b: T, unordered: boolean) {
if (!isIterable(a) || !isIterable(b)) {
if (isPlainObject(a) && isPlainObject(b)) {
return sameIgnoreOrder(Object.entries(a), Object.entries(b), unordered)
return sameIgnoreOrder(Object.entries(a), Object.entries(b), unordered);
}
return a === b
return a === b;
}
const itA = a[Symbol.iterator]()
const itB = b[Symbol.iterator]()
const itA = a[Symbol.iterator]();
const itB = b[Symbol.iterator]();
for (let [aa, bb] = [itA.next(), itB.next()]; ; [aa, bb] = [itA.next(), itB.next()]) {
if (!same(aa.value, bb.value, unordered)) {
return false
return false;
}
if (aa.done !== bb.done) {
return false
return false;
}
if (aa.done) {
return true
return true;
}

@@ -55,16 +67,16 @@ }

function sameIgnoreOrder<T>(a: Iterable<T>, b: Iterable<T>, unordered:boolean) {
const [aa, bb] = [histogram(a), histogram(b)]
function sameIgnoreOrder<T>(a: Iterable<T>, b: Iterable<T>, unordered: boolean) {
const [aa, bb] = [histogram(a), histogram(b)];
if (size(aa) !== size(bb)) {
return false
return false;
}
for (const [key, count] of aa) {
let wasFound = false
let wasFound = false;
for (const [bkey, bcount] of bb) {
if (same(key,bkey, unordered)) {
wasFound = true
if (same(key, bkey, unordered)) {
wasFound = true;
if (bcount !== count) {
return false
return false;
} else {
break
break;
}

@@ -74,7 +86,6 @@ }

if (!wasFound) {
return false
return false;
}
}
return true
return true;
}

@@ -1,7 +0,6 @@

import { getIn } from "./objects";
import { getIn } from './objects';
/**
* Throws if value is not a string
* @param value
* @param errorMessage
*/

@@ -14,7 +13,5 @@ export function assertIsString(value: any, errorMessage = 'Value is not string'): asserts value is string {

//
/**
* Replaced non alphanumeric character with CSS unicode representation
* @see https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
* @param str
* Replaced non alphanumeric character with {@link https://drafts.csswg.org/cssom/#escape-a-character-as-code-point|CSS unicode representation}
* @returns CSS safe string

@@ -28,3 +25,5 @@ */

/**
*/
export enum NamingConvention {

@@ -37,5 +36,5 @@ KebabCase = 'kebab-case',

/**
*
* @param namingConvention
* @returns true if namingConvention is a supported NamingConvention
* Checks if namingConvention is supported
* @returns true if namingConvention is a supported {@link NamingConvention}
*/

@@ -48,4 +47,3 @@ export function isValidNamingConvention(namingConvention: string): namingConvention is NamingConvention {

* Capitalize the first letter of a string
* @param val
* @returns val with the first letter capitalized
*/

@@ -58,8 +56,11 @@ export function capitalizeFirstLetter(val: string): string {

* Breaks down a string to words, dropping non letters and numbers
* @example <caption>Spaces</caption> splitIntoWords("Hello world") => ["Hello", "world"]
* @example <caption>Numbers</caption> splitIntoWords("Hello123world") => ["Hello", "123" "world"]
* @example <caption>Acronyms</caption> splitIntoWords("Hello WRL") => ["Hello", "WRL"]
* @example <caption>Capitalized</caption> splitIntoWords("HelloWorld") => ["Hello", "World"]
* @example <caption>Others characters</caption> splitIntoWords("Hello_world--"") => ["Hello", "world"]
* @param str
* @example
* ```ts
* splitIntoWords("Hello world") // => ["Hello", "world"]
* splitIntoWords("Hello123world") // => ["Hello", "123" "world"]
* splitIntoWords("Hello WRL") // => ["Hello", "WRL"]
* splitIntoWords("HelloWorld") // => ["Hello", "World"]
* splitIntoWords("Hello_world--") // => ["Hello", "world"]
* ```
* @returns An array of words contained in str

@@ -77,4 +78,3 @@ */

* Converts a string to kebab-case
* @param str
* @returns str in kebab-case-convention
*/

@@ -87,4 +87,3 @@ export function toKebabCase(str: string): string {

* Converts a string to PascalCase
* @param str
* @returns str in PascalCaseConvention
*/

@@ -97,7 +96,8 @@ export function toPascalCase(str: string): string {

/**
* Similar to toPascalCase, but drops heading non-letters
* @example toPascalCaseJsIdentifier("123helloWorld") => "HelloWorld"
* @see toPascalCase
* @param str
* @returns str in PascalCaseConvention that starts with a letter
* Similar to {@link toPascalCase}, but drops heading non-letters
* @example
* ```ts
* toPascalCaseJsIdentifier("123helloWorld") // => "HelloWorld"
* ```
*/

@@ -111,4 +111,3 @@ export function toPascalCaseJsIdentifier(str: string): string {

* Converts a string to camelCase
* @param str
* @returns str in camelCaseConvention
*/

@@ -124,5 +123,3 @@ export function toCamelCase(str: string): string {

* Converts string formatting to a naming convention
* @param str
* @param namingConvention
* @returns
*/

@@ -141,3 +138,4 @@ export function toNamingConvention(str: string, namingConvention: NamingConvention): string {

/**
* like toKebabCase, but prepends '-' if first character of input is UpperCase
* like {@link toKebabCase}, but prepends '-' if first character of input is UpperCase
*/

@@ -153,3 +151,4 @@ export function toCSSKebabCase(str: string): string {

/**
* like toCamelCase, but capitalizes first character if input starts with '-'
* like {@link toCamelCase}, but capitalizes first character if input starts with '-'
*/

@@ -165,6 +164,5 @@ export function toCSSCamelCase(str: string): string {

/**
* Finds line an column by position index
* @param content
* @param pos
* @param newline zero based line number and character
* Finds line an column by position index
* @returns zero based line number and character
*/

@@ -203,6 +201,4 @@ export function indexToLineAndColumn(

/**
*
* @param str
* @param substr
* @returns true is str contains substr, ignoring capitalization
* Checks if str contains substr ignoring capitalization
*/

@@ -213,2 +209,10 @@ export function includesCaseInsensitive(str: string, substr: string): boolean {

/**
* Matches the indentation of modified to the one of reference
* @param reference -
* @param modified -
* @param newline -
* @returns
*/
export function equalIdents(reference: string, modified: string, newline = '\n') {

@@ -233,5 +237,6 @@ const referenceArr = reference.split(newline);

* Remove line indentation (heading whitespace)
* @param modified
* @param separator
* @returns
* @param modified-
* @param separator-
* @returns
*/

@@ -247,2 +252,29 @@ export function noIdents(modified: string, separator = '\n') {

/**
* Shifts all indentation to the left
* using the line with the least indentation as a baseline
*/
export function minimalIndent(str: string) {
const lines = str.split('\n');
const min = lines.reduce((min, l) => Math.min(l.replace(/(\s*)(.*)/g, '$1').length, min), 0);
return lines.map((l) => l.slice(min)).join('\n');
}
/**
* Remove white spaces including empty lines
*/
export function noWhiteSpace(str: string) {
return str
.split('\n')
.map((line) => line.replaceAll(/\s+/g, ' ').trim())
.filter((i) => i)
.join('\n');
}
/**
* Checks is value is a string
* @param value -
* @returns
*/
export const isString = (value: unknown): value is string => typeof value === 'string';

@@ -252,7 +284,13 @@

/**
* @param context A context for the compiler
* Similar to templated string,
* given a fixed context object returns a function that parses strings in it
* @param context- A context for the compiler
* @returns A template compiler function which accepts a template and compile it with `context`
* @example
* templateCompilerProvider({ greetings: 'Hello', person: { name: 'Elad' } })('${greetings} ${person.name}!')
* // => Hello Elad!
* ```ts
* const compile = templateCompilerProvider({ greetings: 'Hello', person: { name: 'Elad' } })
* compile('${greetings} ${person.name}!')// => Hello Elad!
* compile('${person.name} is awesome')// => Elad is awesome
* ```
*/

@@ -268,1 +306,25 @@ export function templateCompilerProvider(context: Record<string, any>) {

}
/**
* Generates a string repeating [str] [count] times
*/
export function repeat(str: string, count: number) {
return [...new Array<void>(count)].map(() => str).join('');
}
/**
* Returns a string safe to be used in RegExp
* @see https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
*/
export function escapeRegExp(str: string) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
// $& means the whole matched string
}
/**
* Removes comments from string
* Note that there's lexical no parsing, so stuff like "//'//" will not work
*/
export function naiveStripComments(str:string) {
return str.replaceAll(/\/\*.+?\*\//gs, '').replaceAll(/\s*(?<!:)\/\/.*\n?/g, '')
}
import { expect } from 'chai';
import { getCartesianProductOfArrays } from '..'
import { getCartesianProductOfArrays } from '..';

@@ -40,2 +40,2 @@ describe('getCartesianProductOfArrays', () => {

});
})
});

@@ -1,39 +0,41 @@

import { expect } from "chai"
import { chain } from "../chain"
// eslint-disable-next-line
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import gc from 'expose-gc/function'
import { expect } from 'chai';
import { chain } from '../chain';
// @ts-expect-error no types
import gc from 'expose-gc/function';
const forceGc = gc as () => void;
describe('performance', () => {
it('it faster than the array equivalent function for large iterables', () => {
const veryLargeArray = Array.from(new Array(2 ** 18)).map((_, i) => i % 2 ** 32)
gc()
const arrayStart = performance.now()
const veryLargeArray = Array.from(new Array(2 ** 18)).map((_, i) => i % 2 ** 32);
forceGc();
const arrayStart = performance.now();
const result = veryLargeArray
.map(i => i - 10_000)
.filter(i => i > 0)
.map(i => `${i}`)
.filter(i => i.includes('9'))
.flatMap(i => i.split(''))
.map((i) => i - 10_000)
.filter((i) => i > 0)
.map((i) => `${i}`)
.filter((i) => i.includes('9'))
.flatMap((i) => i.split(''))
// equivalent to "unique"
.reduce((acc, i) => { acc.add(i); return acc }, new Set<string>())
.values()
gc()
const arrayTime = performance.now() - arrayStart
.reduce((acc, i) => {
acc.add(i);
return acc;
}, new Set<string>())
.values();
forceGc();
const arrayTime = performance.now() - arrayStart;
const iterStart = performance.now()
const iterStart = performance.now();
const iterResult = chain(veryLargeArray)
.map(i => i - 10_000)
.filter(i => i > 0)
.map(i => `${i}`)
.filter(i => i.includes('9'))
.flatMap(i => i.split(''))
.unique().iterable
gc()
const iterTime = performance.now() - iterStart
.map((i) => i - 10_000)
.filter((i) => i > 0)
.map((i) => `${i}`)
.filter((i) => i.includes('9'))
.flatMap((i) => i.split(''))
.unique().iterable;
forceGc();
const iterTime = performance.now() - iterStart;
expect([...result]).to.eql([...iterResult])
expect(iterTime).to.be.lessThan(arrayTime)
})
})
expect([...result]).to.eql([...iterResult]);
expect(iterTime).to.be.lessThan(arrayTime);
});
});

@@ -11,11 +11,10 @@ import chai, { expect } from 'chai';

it('passes the call only once', () => {
const fn = stub().returns(true)
const onceFn = once(fn)
expect(fn).to.not.have.been.called
expect(onceFn(1)).to.equal(true)
expect(onceFn(2)).to.equal(true)
expect(fn).to.have.callCount(1)
expect(fn).to.have.been.calledWith(1)
const fn = stub().returns(true);
const onceFn = once(fn);
expect(fn).to.not.have.been.called;
expect(onceFn(1)).to.equal(true);
expect(onceFn(2)).to.equal(true);
expect(fn).to.have.callCount(1);
expect(fn).to.have.been.calledWith(1);
});
});

@@ -1,39 +0,63 @@

import { expect } from "chai"
import { last, at, first, unique, next, prev, concat, flat, map, flatMap, filter, forEach, find, includes, some, every, isEmpty, size, reduce, groupBy } from ".."
import { expect } from 'chai';
import {
last,
at,
first,
unique,
next,
prev,
concat,
flat,
map,
flatMap,
filter,
forEach,
find,
includes,
some,
every,
isEmpty,
size,
reduce,
groupBy,
join,
skip,
} from '../iterables';
describe('iterables', () => {
it('last', () => {
expect(last([1, 2, 3])).to.equal(3)
expect(last([])).to.equal(undefined)
})
expect(last([1, 2, 3])).to.equal(3);
expect(last([])).to.equal(undefined);
});
it('first', () => {
expect(first([1, 2, 3])).to.equal(1)
expect(first([])).to.equal(undefined)
})
expect(first([1, 2, 3])).to.equal(1);
expect(first([])).to.equal(undefined);
});
it('find', () => {
expect(find([0, 1, 2], i => !!i)).to.equal(1)
})
expect(find([0, 1, 2], (i) => !!i)).to.equal(1);
});
it('includes', () => {
expect(includes([0, 1, 2], 2)).to.equal(true)
})
expect(includes([0, 1, 2], 2)).to.equal(true);
});
it('some', () => {
expect(some([0, 1, 2], i => i == 1)).to.equal(true)
expect(some([0, 2], i => i == 1)).to.equal(false)
})
expect(some([0, 1, 2], (i) => i == 1)).to.equal(true);
expect(some([0, 2], (i) => i == 1)).to.equal(false);
});
it('every', () => {
expect(every([1, 2], i => !!i)).to.equal(true)
expect(every([0, 1, 2], i => !!i)).to.equal(false)
})
expect(every([1, 2], (i) => !!i)).to.equal(true);
expect(every([0, 1, 2], (i) => !!i)).to.equal(false);
});
describe('at', () => {
it('returns the element at a positive index', () => {
expect(at([1, 2, 3], 0)).to.equal(1)
expect(at([1, 2, 3], 1)).to.equal(2)
})
expect(at([1, 2, 3], 0)).to.equal(1);
expect(at([1, 2, 3], 1)).to.equal(2);
});
it('returns the element at a negative index', () => {
expect(at([1, 2, 3], -1)).to.equal(3)
})
expect(at([1, 2, 3], -1)).to.equal(3);
});
it('returns undefined when out of bounds', () => {
expect(at([1, 2, 3], 4)).to.equal(undefined)
expect(at([1, 2, 3], -4)).to.equal(undefined)
})
})
expect(at([1, 2, 3], 4)).to.equal(undefined);
expect(at([1, 2, 3], -4)).to.equal(undefined);
});
});

@@ -43,3 +67,3 @@ describe('unique', () => {

expect([...unique(['1', 1, 1, true])]).to.eql(['1', 1, true]);
expect([...unique([0,1,2,3], i => i%2)]).to.eql([0,1]);
expect([...unique([0, 1, 2, 3], (i) => i % 2)]).to.eql([0, 1]);
});

@@ -72,42 +96,60 @@ });

expect([...concat([0, 1, 2], [3], [4, 5])]).to.eql([0, 1, 2, 3, 4, 5]);
})
});
it(`flat`, () => {
expect([...flat([0, [1, 2]])]).to.eql([0, 1, 2]);
expect([...flat([0, [1, [2]]], true)]).to.eql([0, 1, 2]);
})
});
it(`isEmpty`, () => {
expect(isEmpty([])).to.eql(true);
expect(isEmpty([1])).to.eql(false);
})
});
it(`size`, () => {
expect(size([])).to.eql(0);
expect(size([0, 1])).to.eql(2);
})
});
it(`map`, () => {
expect([...map([0, 1, 2], i => i ** 2)]).to.eql([0, 1, 4]);
})
expect([...map([0, 1, 2], (i) => i ** 2)]).to.eql([0, 1, 4]);
});
it(`flatMap`, () => {
expect([...flatMap([0, 1, 2], i => i ? [i, i] : i)]).to.eql([0, 1, 1, 2, 2]);
})
expect([...flatMap([0, 1, 2], (i) => (i ? [i, i] : i))]).to.eql([0, 1, 1, 2, 2]);
});
it(`filter`, () => {
expect([...filter([0, 1, 2], i => !!i)]).to.eql([1, 2]);
})
expect([...filter([0, 1, 2], (i) => !!i)]).to.eql([1, 2]);
});
it(`forEach`, () => {
const r = [] as number[]
forEach([0, 1, 2], i => r.push(i))
const r = [] as number[];
forEach([0, 1, 2], (i) => r.push(i));
expect(r).to.eql([0, 1, 2]);
})
it('reduce', ()=>{
const input = [0,1,2,3]
const reducer = (acc:number, i:number) => acc + i
expect(reduce(input, reducer, 0)).to.equal(input.reduce(reducer, 0))
})
it('groupBy', ()=>{
expect(groupBy([{a:1, b:0},{a:1,b:1}, {a:2}], 'a')).to.eql(
});
it('reduce', () => {
const input = [0, 1, 2, 3];
const reducer = (acc: number, i: number) => acc + i;
expect(reduce(input, reducer, 0)).to.equal(input.reduce(reducer, 0));
});
it('join', () => {
expect(join(['0', '1', '2'], ',')).to.eql('0,1,2');
expect(join([], ',')).to.eql('');
expect(join(null, ',')).to.eql('');
expect(join(['0'], ',')).to.eql('0');
});
it('skip', () => {
expect([...skip([0, 1, 2, 3], 1)]).to.eql([1, 2, 3]);
expect([...skip([], 1)]).to.eql([]);
expect([...skip([0, 1], 0)]).to.eql([0, 1]);
expect([...skip([0, 1], 3)]).to.eql([]);
});
it('groupBy', () => {
expect(groupBy([{ a: 1, b: 0 }, { a: 1, b: 1 }, { a: 2 }], 'a')).to.eql(
new Map([
[1, [{a:1,b:0}, {a:1, b:1}]],
[2, [{a:2}]]
[
1,
[
{ a: 1, b: 0 },
{ a: 1, b: 1 },
],
],
[2, [{ a: 2 }]],
])
)
})
})
);
});
});

@@ -1,23 +0,23 @@

import { expect } from "chai"
import { getValue } from "../maps"
import { expect } from 'chai';
import { getValue } from '../maps';
describe('maps', ()=>{
describe('maps', () => {
describe('getValue', () => {
const map = new Map([[0, 1]])
const obj = {'0':1}
const map = new Map([[0, 1]]);
const obj = { '0': 1 };
it('thrown when the value is missing', () => {
expect(() => {
getValue(map, 2, 'missing!')
}).to.throw('missing!')
})
getValue(map, 2, 'missing!');
}).to.throw('missing!');
});
it('thrown when the map is nullish', () => {
expect(() => {
getValue(null, 2, 'no map')
}).to.throw('no map')
})
getValue(null, 2, 'no map');
}).to.throw('no map');
});
it('returns the value', () => {
expect(getValue(map, 0)).to.equal(1)
expect(getValue(obj, '0')).to.equal(1)
})
})
})
expect(getValue(map, 0)).to.equal(1);
expect(getValue(obj, '0')).to.equal(1);
});
});
});

@@ -14,15 +14,19 @@ import { expect } from 'chai';

it(`merges to POJOs`, () => {
expect(defaults({ a: 0, b: 1 }, { a: 1, b: 2, c: 3 })).to.eql({ a: 0, b: 1, c: 3 })
})
expect(defaults({ a: 0, b: 1 }, { a: 1, b: 2, c: 3 })).to.eql({ a: 0, b: 1, c: 3 });
});
it(`deep=true (default)`, () => {
expect(defaults({ a: { a: 10, b: 20 } }, { a: { a: 20, c: 30 } })).to.eql({ a: { a: 10, b: 20, c: 30 } })
})
expect(defaults({ a: { a: 10, b: 20 } }, { a: { a: 20, c: 30 } })).to.eql({ a: { a: 10, b: 20, c: 30 } });
});
it(`deep=false`, () => {
expect(defaults({ a: { a: 10 } }, { a: { b: 20 } }, false)).to.eql({ a: { a: 10 } })
})
expect(defaults({ a: { a: 10 } }, { a: { b: 20 } }, false)).to.eql({ a: { a: 10 } });
});
it(`shouldUseDefault arg`, () => {
expect(defaults({ a: { a: 10, b: 20 } }, { a: { a: 20, c: 30 } }, true, i => i === 10)).to.eql({ a: { a: 20, b: 20, c: 30 } })
expect(defaults({ a: { a: 10, b: 20 } }, { a: { a: 20, c: 30 } }, true, (_, key) => key === 'a.a')).to.eql({ a: { a: 20, b: 20, c: 30 } })
})
})
expect(defaults({ a: { a: 10, b: 20 } }, { a: { a: 20, c: 30 } }, true, (i) => i === 10)).to.eql({
a: { a: 20, b: 20, c: 30 },
});
expect(defaults({ a: { a: 10, b: 20 } }, { a: { a: 20, c: 30 } }, true, (_, key) => key === 'a.a')).to.eql({
a: { a: 20, b: 20, c: 30 },
});
});
});

@@ -32,25 +36,25 @@ describe('remap', () => {

const input = { a: 0, b: 1 };
const output: { c: number, b: number } = remap(input, { a: 'c' })
expect(output).to.eql({ c: 0, b: 1 })
})
const output: { c: number; b: number } = remap(input, { a: 'c' });
expect(output).to.eql({ c: 0, b: 1 });
});
it('removes keys mapped to remap.DELETE', () => {
const input = { a: 0, b: 1 };
const output: { b: number } = remap(input, { a: remap.DELETE })
expect(output).to.eql({ b: 1 })
})
})
const output: { b: number } = remap(input, { a: remap.DELETE });
expect(output).to.eql({ b: 1 });
});
});
describe('isPlainObject', () => {
it('returns true for POJO', () => {
class A { }
expect(isPlainObject({})).to.be.true
expect(isPlainObject(null)).to.be.false
expect(isPlainObject(undefined)).to.be.false
expect(isPlainObject(new A())).to.be.false
expect(isPlainObject(new Map())).to.be.false
})
class A {}
expect(isPlainObject({})).to.be.true;
expect(isPlainObject(null)).to.be.false;
expect(isPlainObject(undefined)).to.be.false;
expect(isPlainObject(new A())).to.be.false;
expect(isPlainObject(new Map())).to.be.false;
});
it('allows direct access to fields', () => {
const a = { a: 1 }
expect(isPlainObject(a) && a.a).to.eql(1)
})
})
const a = { a: 1 };
expect(isPlainObject(a) && a.a).to.eql(1);
});
});

@@ -1,79 +0,79 @@

import { expect } from "chai"
import { expect } from 'chai';
// eslint-disable-next-line
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { same } from "../same"
import { toMap } from "../types"
import { same } from '../same';
import { toMap } from '../types';
describe('same', () => {
describe('types unaffected by "unordered" param', ()=>{
describe('types unaffected by "unordered" param', () => {
it('compares native values', () => {
expect(same(1, 1)).to.eql(true)
expect(same(1, 0)).to.eql(false)
expect(same(null, undefined)).to.eql(false)
expect(same(null, null)).to.eql(true)
expect(same('a', 'a')).to.eql(true)
expect(same('a', 'b')).to.eql(false)
})
expect(same(1, 1)).to.eql(true);
expect(same(1, 0)).to.eql(false);
expect(same(null, undefined)).to.eql(false);
expect(same(null, null)).to.eql(true);
expect(same('a', 'a')).to.eql(true);
expect(same('a', 'b')).to.eql(false);
});
it('compares POJOs', () => {
expect(same({}, {})).to.eql(true)
expect(same({ a: 1 }, { a: 1 })).to.eql(true)
expect(same({ a: 1 }, { a: 2 })).to.eql(false)
expect(same({ a: undefined }, {})).to.eql(false)
expect(same({ a: undefined }, { a: null })).to.eql(false)
expect(same({ a: 1, b: 2 }, { b: 2, a: 1 })).to.eql(true)
expect(same({ a: { b: 1 } }, { a: { b: 1 } })).to.eql(true)
expect(same({ a: { b: 1 } }, { a: { b: 2 } })).to.eql(false)
})
expect(same({}, {})).to.eql(true);
expect(same({ a: 1 }, { a: 1 })).to.eql(true);
expect(same({ a: 1 }, { a: 2 })).to.eql(false);
expect(same({ a: undefined }, {})).to.eql(false);
expect(same({ a: undefined }, { a: null })).to.eql(false);
expect(same({ a: 1, b: 2 }, { b: 2, a: 1 })).to.eql(true);
expect(same({ a: { b: 1 } }, { a: { b: 1 } })).to.eql(true);
expect(same({ a: { b: 1 } }, { a: { b: 2 } })).to.eql(false);
});
it('compares Maps', () => {
expect(same(new Map(), new Map())).to.eql(true)
expect(same(toMap({}), toMap({}))).to.eql(true)
expect(same(toMap({ a: 1 }), toMap({ a: 1 }))).to.eql(true)
expect(same(toMap({ a: 1 }), toMap({ a: 2 }))).to.eql(false)
expect(same(toMap({ a: undefined }), toMap({}))).to.eql(false)
expect(same(toMap({ a: undefined }), toMap({ a: null }))).to.eql(false)
expect(same(toMap({ a: 1, b: 2 }), toMap({ b: 2, a: 1 }))).to.eql(true)
expect(same(toMap({ a: { b: 1 } }), toMap({ a: { b: 1 } }))).to.eql(true)
expect(same(toMap({ a: { b: 1 } }), toMap({ a: { b: 2 } }))).to.eql(false)
})
expect(same(new Map(), new Map())).to.eql(true);
expect(same(toMap({}), toMap({}))).to.eql(true);
expect(same(toMap({ a: 1 }), toMap({ a: 1 }))).to.eql(true);
expect(same(toMap({ a: 1 }), toMap({ a: 2 }))).to.eql(false);
expect(same(toMap({ a: undefined }), toMap({}))).to.eql(false);
expect(same(toMap({ a: undefined }), toMap({ a: null }))).to.eql(false);
expect(same(toMap({ a: 1, b: 2 }), toMap({ b: 2, a: 1 }))).to.eql(true);
expect(same(toMap({ a: { b: 1 } }), toMap({ a: { b: 1 } }))).to.eql(true);
expect(same(toMap({ a: { b: 1 } }), toMap({ a: { b: 2 } }))).to.eql(false);
});
it('compares Sets', () => {
expect(same(new Set(), new Set())).to.eql(true)
expect(same(new Set([1]), new Set([1]))).to.eql(true)
expect(same(new Set([1, 2, 3]), new Set([1, 2, 3]))).to.eql(true)
expect(same(new Set([1]), new Set([2]))).to.eql(false)
})
})
expect(same(new Set(), new Set())).to.eql(true);
expect(same(new Set([1]), new Set([1]))).to.eql(true);
expect(same(new Set([1, 2, 3]), new Set([1, 2, 3]))).to.eql(true);
expect(same(new Set([1]), new Set([2]))).to.eql(false);
});
});
describe('ordered', () => {
it('compares flat arrays', () => {
expect(same([],[])).to.eql(true)
expect(same([1,2],[1,2])).to.eql(true)
expect(same([1,2],[2,1])).to.eql(false)
})
expect(same([], [])).to.eql(true);
expect(same([1, 2], [1, 2])).to.eql(true);
expect(same([1, 2], [2, 1])).to.eql(false);
});
it('compares iterables', () => {
expect(same([1,2][Symbol.iterator](),[1,2][Symbol.iterator]())).to.eql(true)
expect(same([1,2][Symbol.iterator](),[2,1][Symbol.iterator]())).to.eql(false)
})
expect(same([1, 2][Symbol.iterator](), [1, 2][Symbol.iterator]())).to.eql(true);
expect(same([1, 2][Symbol.iterator](), [2, 1][Symbol.iterator]())).to.eql(false);
});
it('compares nested arrays', () => {
expect(same([[[]]],[[[]]])).to.eql(true)
expect(same([1,[2,3]],[1,[2,3]])).to.eql(true)
expect(same([1,[3,2]],[1,[3,2]])).to.eql(true)
})
it('ignores the order within objects, maps and sets', ()=>{
expect(same([{b:0, a:1}],[{a:1, b:0}])).to.eql(true)
expect(same([toMap({b:0, a:1})],[toMap({a:1, b:0})])).to.eql(true)
expect(same([new Set([1,2])],[new Set([2,1])])).to.eql(true)
})
it('checks the order of arrays within objects', ()=>{
expect(same([{a:[0,1]}],[{a:[1,0]}])).to.eql(false)
})
})
describe('unordered array', ()=>{
it('ignores order of flat arrays', ()=>{
expect(same([0,1,2],[2,1,0], true)).to.eql(true)
expect(same([0,1,2],[2,1,0], true)).to.eql(true)
})
it('ignores order of nested arrays', ()=>{
expect(same([0,[1,2]],[[2,1],0], true)).to.eql(true)
})
})
})
expect(same([[[]]], [[[]]])).to.eql(true);
expect(same([1, [2, 3]], [1, [2, 3]])).to.eql(true);
expect(same([1, [3, 2]], [1, [3, 2]])).to.eql(true);
});
it('ignores the order within objects, maps and sets', () => {
expect(same([{ b: 0, a: 1 }], [{ a: 1, b: 0 }])).to.eql(true);
expect(same([toMap({ b: 0, a: 1 })], [toMap({ a: 1, b: 0 })])).to.eql(true);
expect(same([new Set([1, 2])], [new Set([2, 1])])).to.eql(true);
});
it('checks the order of arrays within objects', () => {
expect(same([{ a: [0, 1] }], [{ a: [1, 0] }])).to.eql(false);
});
});
describe('unordered array', () => {
it('ignores order of flat arrays', () => {
expect(same([0, 1, 2], [2, 1, 0], true)).to.eql(true);
expect(same([0, 1, 2], [2, 1, 0], true)).to.eql(true);
});
it('ignores order of nested arrays', () => {
expect(same([0, [1, 2]], [[2, 1], 0], true)).to.eql(true);
});
});
});

@@ -1,2 +0,2 @@

import { splitIntoWords, toCamelCase, toKebabCase, toPascalCase } from '..';
import { noWhiteSpace, repeat, splitIntoWords, naiveStripComments, toCamelCase, toKebabCase, toPascalCase } from '..';
import { expect } from 'chai';

@@ -37,1 +37,30 @@

});
it('repeat', () => {
expect(repeat('[]', 3)).to.eql('[][][]');
});
it('noWhiteSpace', () => {
expect(noWhiteSpace('no whitespace')).to.equal('no whitespace');
expect(noWhiteSpace('\t\ttabs\t')).to.equal('tabs');
expect(noWhiteSpace(' single line ')).to.equal('single line');
expect(noWhiteSpace(' multiple \r\n lines ')).to.equal('multiple\nlines');
expect(noWhiteSpace(' empty \n\n \n lines ')).to.equal('empty\nlines');
});
describe('stripComments', ()=>{
it('removes /* */ comments', ()=>{
expect(naiveStripComments(`no /* success removing */comments`)).to.equal('no comments')
expect(naiveStripComments(`no /*
success removing
*/comments`)).to.equal('no comments')
})
it('removes // comments', ()=>{
expect(naiveStripComments(`no comments// after code`)).to.equal('no comments')
expect(naiveStripComments(`// line comments\nno comments`)).to.equal('no comments')
})
it('does not identify :// as comment', ()=>{
expect(naiveStripComments(`http://url //my site`)).to.equal('http://url')
})
})
{
"extends": "../../../tsconfig.base.json",
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../dist/esm",
"module": "ESNext"
},
"references": []
"module": "esnext"
}
}

@@ -0,8 +1,45 @@

/**
* The resolved value of T (if a promise, otherwise simply T)
*/
export type Awaited<T> = T extends PromiseLike<infer U> ? U : T;
export type Nullable<T> = T|null|undefined
export const isMap = <K = any, V = any>(m: any): m is Map<K, V> => m instanceof Map
export const isSet = <V = any>(m: any): m is Set<V> => m instanceof Set
/**
* T or null/undefined
*/
export type Nullable<T> = T | null | undefined;
/**
* Validates s is an instance of Map
* @returns true if s is a Map
*/
export const isMap = <K = any, V = any>(m: any): m is Map<K, V> => m instanceof Map;
/**
* Validates s is an instance of Set
* @returns true if s is a Set
*/
export const isSet = <V = any>(s: any): s is Set<V> => s instanceof Set;
/**
* Given a value of type Nullable<T>, validates value is T
* @returns true if value is defined (not null or undefined)
*/
export function isDefined<T>(value: Nullable<T>): value is T {
return value !== null && value !== undefined;
}
export const toMap = (a:object) => new Map(Object.entries(a))
/**
* Coverts and object into a Map
* @param obj - POJO
* @returns A map with the same entries as obj
*/
export const toMap = (obj: object) => new Map(Object.entries(obj));
/**
* Make an intersection type from union
* @example
* ```ts
* const a:UnionToIntersection<{a:string}|{b:string}> = {a:'ok', b:'also ok'}
* ```
*/
export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc