Giter Club home page Giter Club logo

common's Introduction

Metarhia Common Library

ci status snyk npm version npm downloads/month npm downloads license

Installation

$ npm install @metarhia/common

API

splitAt(index, array)

  • index: <number> index defining end of first part and start of second
  • array: <Array> to be split

Returns: <Array> tuple with two parts of the array

Split array into two parts

shuffle(arr)

Returns: <Array>

Shuffle an array

sample(arr)

Returns: <any>

Random element from array

range(from, to)

Returns: <Array>

Generate int array from given range

Example:

range(1, 5);

Result:

[1, 2, 3, 4, 5];

sequence(seq[, max])

Returns: <Array>

Generate int array from sequence syntax

Example:

list: sequence([81, 82, 83]);

Result:

[81, 82, 83];

Example:

range from..to: sequence([81,,83]) = [81, 82, 83];

Result:

[81, 82, 83];

Example:

range from..count: sequence([81, [3]]) = [81, 82, 83];

Result:

[81, 82, 83];

Example:

range from..max-to: sequence([81, [-2]], 5) = [81, 82, 83];

Result:

[81, 82, 83];

last(arr)

Returns: <any> element

Get last element of array

pushSame(arr, n, value)

Returns: <number> new value of arr.length

Push single value multiple times

checkLogin(login, required[, optional])

  • login: <string> login to test
  • required: <Array> required tests configs
  • optional: <Array> optional tests configs, defalult: []

Returns: <AuthenticationStrength>

Function that tests the login

checkPassword(password, required[, optional])

  • password: <string> password to test
  • required: <Array> required tests configs
  • optional: <Array> optional tests configs, default: []

Returns: <AuthenticationStrength>

Function that tests the password

checkLoginPassword(login, password, required[, optional])

  • login: <string> login to test
  • password: <string> password to test
  • required: <Array> required tests configs
  • optional: <Array> optional tests configs, default: []

Returns: <AuthenticationStrength>

Function that tests the login with password

class BTree

BTree.prototype.constructor(degree = DEFAULT_DEGREE)

BTree.prototype.get(key)

BTree.prototype.iterator(start, finish)

BTree.prototype.remove(key)

BTree.prototype.set(key, data)

cache()

Returns: <Cache>

Create Cache, enhanced Map

class Cache extends Map

Cache.prototype.constructor()

Cache.prototype.add(key, val)

  • key: <string> key
  • val: <any> associated value

Add key-value pair to cache

Cache.prototype.clr(prefix[, fn])

  • prefix: <string> to compare with beginning of the key
  • fn: <Function> (optional)
    • key: <string> key
    • val: <any> associative value to be called on each key

Clear cache elements that start with prefix

Cache.prototype.del(key)

Delete cache element

falseness()

Returns: <boolean> always false

Empty function

trueness()

Returns: <boolean> always true

Empty function

emptiness()

Empty function

nop(callback)

  • callback: <Function> callback to be called with (null)

Empty asynchronous callback-last single-argument function

noop(empty, callback)

  • empty: <any> incoming value to be ignored
  • callback: <Function> callback to be called with (null, null)

Empty asynchronous callback-last double-argument function

once([fn])

Returns: <Function> function(...args) wrapped callback

Wrap function: call once, not null

unsafeCallback(args)

Returns: <Function>|<null> callback if any

Extract callback function

It's unsafe: may return null, allows multiple calls

safeCallback(args)

Returns: <Function> callback or common.emptiness if there is no callback

Extract callback

requiredCallback(args)

Returns: <Function> extracted callback

Extract callback

Throws: <TypeError> if there is no callback

onceCallback(args)

Returns: <Function> callback or common.emptiness if there is no callback

Extract callback and make it safe

Wrap callback with once()

safeFunction(fn)

Returns: <Function> function or common.emptiness if fn is not a function

Check function and make it safe

unsafeFunction(fn)

Returns: <Function>|<null> function or null if fn is not a function

Check function

id(x)

  • x: <any> incoming value which will be returned

Returns: <any> incoming value

Identity function

asyncId(x, callback)

  • x: <any> incoming value which will be returned into the callback
  • callback: <Function> callback to be called with first argument

Async identity function

isScalar(value)

  • value: <any>

Returns: <boolean>

Check if value is scalar

copy(ds)

Returns: <Object[]>

Copy dataset (copy objects to new array)

clone(obj)

Returns: <Object>|<Array>

Clone object or array

duplicate(obj)

Returns: <Object>|<Array>

Duplicate object or array (properly handles prototype and circular links)

getByPath(data, dataPath)

Returns: <any> value

Read property by dot-separated path

setByPath(data, dataPath, value)

Set property by dot-separated path

deleteByPath(data, dataPath)

Returns: <boolean>

Delete property by dot-separated path

merge(...args)

  • args: <Array[]> arrays with elements to be merged

Returns: <Array>

Distinctly merge multiple arrays

mergeObjects(merger, ...objs)

Returns: <Object>

Merge multiple objects with merger

class Enum

Enum.NaE

  • <Symbol> Not an Enum

Enum.from(...args)

Enum.prototype.constructor()

forwardEvents(from, to[, events])

Forward events from one EventEmitter to another

Example:

forwardEvents(from, to);

Example:

forwardEvents(from, to, 'eventName');

Example:

forwardEvents(from, to, { eventName: 'newEventName' });

Example:

forwardEvents(from, to, ['eventName1', 'eventName2']);

emitter()

Returns: <EventEmitter>

Create EnhancedEmitter, enhanced EventEmitter

with wildcard and forward method

class EnhancedEmitter extends EventEmitter

EnhancedEmitter.prototype.constructor()

EnhancedEmitter.prototype.emit(...args)

  • args: <Array> arguments to be passed

Call listener with provided arguments

EnhancedEmitter.prototype.forward(to, events)

Forward events from one EventEmitter to another

class Flags

Flags.from(...args)

Flags.prototype.constructor(...args)

partial(fn, ...args)

Returns: <Function> function(...rest)

Partially apply arguments to function

omap(mapFn, obj)

  • mapFn: <Function> to apply to every field value
  • obj: <Object> which fields used for mapping

Returns: <Object> with same reference but with transformed fields

Map object fields with provided function

compose(...fns)

  • fns: <Array> functions to be composed

Returns: <Function> function(...args), composed

  • args: <Array> arguments to be passed to the first function

Compose multiple functions into one

maybe(fn, defVal[, value])

  • fn: <Function>
  • defVal: <any> default value
  • value: <any> (optional), value

Returns: <any> result of fn or defVal

Apply given function to value or default value

zip(...arrays)

Returns: <Array> length is minimal of input arrays length, element with index i of resulting array is array with elements with index i from input array

Zip several arrays into one

replicate(count, elem)

  • count: <number> new array length
  • elem: <any> value to replicate

Returns: <Array> replicated

Create array of replicated values

zipWith(fn, ...arrays)

Returns: <Array> zipped, element with index i of resulting array is result of fn called with arguments from arrays

Zip arrays using specific function

curryUntil(condition, fn, ...args)

Returns: <Function> function(...args), curried

Curry function until the condition is met

curryN(fn, count, ...args)

  • fn: <Function> to be curried
  • count: <number> of times function should be curried
  • args: <Array> arguments for first currying

Returns: <Function> curried given times count

Curry fn count times, first curry uses args for first currying

curryTwice(fn)

Returns: <Function> to pass arguments that returns curried fn

Curry function curry with fn

curry(fn, ...param)

Returns: <Function> function(...args), curried

Curry function with given arguments

applyArgs(...args)

  • args: <Array> arguments to save in closure

Returns: <Function> returns: <any>, result of fn(...args)

Apply arguments

either(fn)

Returns: <Function> function(...args), returns: <any>, result of fn(arg), where arg - first valid element of args

  • args: <Array> arguments to iterate

Get first not errored result of fn

Throws: <Error> if fn throws it

restLeft(fn)

  • fn: <Function> function(args, ...namedArgs, callback)
    • args: <Array> rest of spreadArgs created by excluding namedArgs
    • namedArgs: <Array> first values of spreadArgs, length is based upon interface of fn
    • callback: <Function> callback, last argument of spreadArgs

Returns: <Function> function(...spreadArgs)

  • spreadArgs: <Array> arguments to be added

Rest left, transform function

mkdirp(dir, mode, cb)

mkdirpPromise(dir, mode = MKDIRP_DEFAULT_MODE)

rmdirp(dir, cb)

rmRecursive(path, callback)

Recursively remove directory

async rmRecursivePromise(path)

  • path: <string> path to a file or directory to be removed

Returns: <Promise>

Recursively remove directory

generateKey(length, possible)

Returns: <string> key

Generate random key

generateGUID()

Returns: <string> GUID

Generate an RFC4122-compliant GUID (UUID v4)

generateToken(secret, characters, length)

Returns: <string> token

Generate random Token

crcToken(secret, key)

Returns: <string> crc

Calculate Token crc

validateToken(secret, token)

Returns: <boolean>

Validate Token

hash(password, salt)

Returns: <string> hash

Calculate hash with salt

validateHash(hashValue, password, salt)

Returns: <boolean>

Validate hash

generateStorageKey()

Returns: <string[]> [folder1, folder2, code]

Generate file storage key

idToChunks(id)

Returns: <Array> minimal length is 2 which contains hex strings with length of 4

Convert id to array of hex strings

idToPath(id)

Returns: <string>

Convert id to file path

pathToId(path)

Returns: <number>

Convert file path to id

class Int64

Int64.add(a, b)

Int64.and(a, b)

Int64.cmp(a, b)

Int64.div(a, b)

Int64.mod(a, b)

Int64.mult(a, b)

Int64.not(a)

Int64.one()

Int64.or(a, b)

Int64.shiftLeft(a, b)

Int64.shiftRight(a, b)

Int64.sub(a, b)

Int64.xor(a, b)

Int64.zero()

Int64.prototype.constructor(value)

Int64.prototype.add(b)

Int64.prototype.and(b)

Int64.prototype.dec()

Int64.prototype.inc()

Int64.prototype.not()

Int64.prototype.or(b)

Int64.prototype.shiftLeft(b)

Int64.prototype.shiftRight(b)

Int64.prototype.shiftRightArithmetic(b)

Int64.prototype.shiftRightLogical(b)

Int64.prototype.sub(b)

Int64.prototype.toInt32()

Int64.prototype.toJSON()

Int64.prototype.toPostgres()

Int64.prototype.toString(radix = 10)

Int64.prototype.toUint32()

Int64.prototype.xor(b)

class Iterator

Iterator.indices(arr)

  • arr: <Array> array-like object to create indices from

Returns: <Iterator>

Create iterator over indices of an array

Iterator.range(start, stop[, step])

Returns: <Iterator>

Create iterator iterating over the range

Iterator.zip(...iterators)

Returns: <Iterator>

Create iterator by zipping multiple provided iterators into one

Iterator.prototype.constructor(base)

Iterator.prototype.apply(fn)

Returns: the result of fn(this) call.

Call a function with this. Will be equivalent to calling fn(it).

Iterator.prototype.chain(...iterators)

Iterator.prototype.chainApply(fn)

Returns: <Iterator> result of fn(this) wrapped in an Iterator.

Call a function with this and wrap the result in an Iterator.

Example:

iter([1, 2])
  .chainApply(([a, b]) => [a + b, a - b])
  .join(', ');

Result:

'3, -1';

Iterator.prototype.collectTo(CollectionClass)

Iterator.prototype.collectWith(obj, collector)

Iterator.prototype.count()

Iterator.prototype.each(fn, thisArg)

Iterator.prototype.enumerate()

Iterator.prototype.every(predicate, thisArg)

Iterator.prototype.filter(predicate, thisArg)

Iterator.prototype.filterMap(mapper[, thisArg[, filterValue]])

  • mapper: <Function> function that maps values and returns either new value that will be the next value of the new iterator or filterValue that will be ignored.
    • value: <any> iterator element
  • thisArg: <any> value to be used as this when calling mapper
  • filterValue: <any> value to filter out mapper results.

Creates an iterator that both filters and maps with the passed mapper.

This iterator will call mapper on each element and if mapper returns NOT filterValue it will be returned, otherwise it is ignored.

Iterator.prototype.find(predicate, thisArg)

Iterator.prototype.findCompare(comparator[, accessor[, thisArg]])

  • comparator: <Function> returns true if new value should be accepted
    • currValue: <any> current value, starts with undefined
    • nextValue: <any> next value
    • Returns: <boolean> true if next value should be accepted
  • accessor: <Function> gets value to compare by, current iterator value is used by default
    • value: <any> current iterator value
    • Returns: <any> value to compare by
  • thisArg: <any> value to be used as this when calling accessor and comparator

Returns: last iterator value where comparator returned true, <undefined> by default

Find value in this iterator by comparing every value with

the found one using comparator

Iterator.prototype.firstNonNullable([defaultValue])

  • defaultValue: <any> value to return if this iterator doesn't have non-nullable values
  • Returns: first non-nullable value or <defaultValue>

Finds first non-nullable value in this iterator

Iterator.prototype.flat(depth = 1)

Iterator.prototype.flatMap(mapper, thisArg)

Iterator.prototype.forEach(fn, thisArg)

Iterator.prototype.groupBy(classifier[, thisArg])

  • classifier: <Function> gets value to group by
    • value: <any> current iterator value
    • Returns: <any> value to group by
  • thisArg: <any> value to be used as this when calling classifier
  • Returns: <Map> map with arrays of iterator values grouped by keys returned by classifier

Consumes an iterator grouping values by keys

Iterator.prototype.includes(element)

Iterator.prototype.join(sep = ', ', prefix = '', suffix = '')

Iterator.prototype.last([defaultValue])

  • defaultValue: <any> value to be used if iterator is empty

Returns: <any>|<undefined> last value of this iterator or <undefined>

Consumes an iterator returning last iterator value

Iterator.prototype.map(mapper, thisArg)

Iterator.prototype.max([accessor[, thisArg]])

  • accessor: <Function> gets value to compare by, current iterator value is used by default
    • value: <any> current iterator value
    • Returns: <any> value to compare by
  • thisArg: <any> value to be used as this when calling accessor

Returns: element with maximum value or <undefined> if iterator is empty

Find the maximum value in this iterator

Iterator.prototype.min([accessor[, thisArg]])

  • accessor: <Function> gets value to compare by, current iterator value is used by default
    • value: <any> current iterator value
    • Returns: <any> value to compare by
  • thisArg: <any> value to be used as this when calling accessor

Returns: element with minimum value or <undefined> if iterator is empty

Find the minimum value in this iterator

Iterator.prototype.next()

Iterator.prototype.partition(predicate[, thisArg])

  • predicate: <Function> function returns a value to partition this iterator
    • value: <any> current iterator element
    • Returns: <boolean>|<number> key denoting resulting partition this value will be assigned to. Number denotes index in the resulting array. Boolean will be cast to number
  • thisArg: <any> value to be used as this when calling predicate
  • Returns: <Array> array of partitions (arrays), will always have at least 2 arrays in it

Consumes an iterator, partitioning it into Arrays

Iterator.prototype.reduce(reducer, initialValue)

Iterator.prototype.skip(amount)

Iterator.prototype.skipWhile(predicate, thisArg)

Iterator.prototype.some(predicate, thisArg)

Iterator.prototype.someCount(predicate, count, thisArg)

Iterator.prototype.take(amount)

Iterator.prototype.takeWhile(predicate, thisArg)

Iterator.prototype.toArray()

Iterator.prototype.toObject()

Transforms an iterator of key-value pairs into an object.

This is similar to what Object.fromEntries() would offer.

Iterator.prototype.zip(...iterators)

iter(base)

iterEntries(obj)

iterKeys(obj)

iterValues(obj)

cryptoPrefetcher(bufSize, valueSize)

  • bufSize: <number> size in bytes of the buffer to preallocate
  • valueSize: <number> size in bytes of the produced chunks

Create prefetcher to use when crypto.randomBytes is required to generate

multiple same-size values. bufSize must be a multiple of valueSize for this to work.

random(min, max)

Returns: <number>

Generate random integer value in given range

cryptoRandom()

Returns: <number>

Generate random number in the range from 0 inclusive up to

but not including 1 (same as Math.random), using crypto-secure number generator.

methods(iface)

Returns: <string[]> method names

List method names

properties(iface)

Returns: <string[]> property names

List property names

ipToInt([ip])

  • ip: <string> (optional), default: '127.0.0.1', IP address

Returns: <number>

Convert IP string to number

localIPs()

Returns: <string[]>

Get local network interfaces

parseHost(host)

  • host: <string> host or empty string, may contain :port

Returns: <string> host without port but not empty

Parse host string

override(obj, fn)

  • obj: <Object> containing method to override
  • fn: <Function> name will be used to find method

Override method: save old to fn.inherited

Previous function will be accessible by obj.fnName.inherited

mixin(target, source)

Mixin for ES6 classes without overriding existing methods

class Pool

Pool.prototype.constructor(factory = null)

Pool.prototype.get()

Pool.prototype.put(value)

sortComparePriority(priority, s1, s2)

Returns: <number>

Compare for array.sort with priority

Example:

files.sort(common.sortComparePriority);

sortCompareDirectories(a, b)

Returns: <number>

Compare for array.sort, directories first

Example:

files.sort(sortCompareDirectories);

sortCompareByName(a, b)

Returns: <number>

Compare for array.sort

Example:

files.sort(sortCompareByName);

class MemoryWritable extends Writable

MemoryWritable.prototype.constructor([sizeLimit])

  • sizeLimit: <number>|<string> limit of the internal buffer size specified as number in bytes or as string in format supported by common.bytesToSize(). Defaults to 8 MB

async MemoryWritable.prototype.getData([encoding])

  • encoding: <string> encoding to convert the resulting data to, must be a valid <Buffer> encoding

Returns: <Promise>

Return a Promise that will be resolved with all the written data once it

becomes available.

subst(tpl, data, dataPath, escapeHtml)

  • tpl: <string> template body
  • data: <Object> hash, data structure to visualize
  • dataPath: <string> current position in data structure
  • escapeHtml: <boolean> escape html special characters if true

Returns: <string>

Substitute variables

htmlEscape(content)

Returns: <string>

Escape html characters

Example:

htmlEscape('5>=5') = '5&lt;=5';

fileExt(fileName)

Returns: <string>

Extract file extension in lower case without dot

Example:

fileExt('/dir/file.txt');

Result:

'txt';

removeExt(fileName)

Returns: <string>

Remove file extension from file name

Example:

fileExt('file.txt');

Result:

'file';

spinalToCamel(name)

Returns: <string>

Convert spinal case to camel case

escapeRegExp(s)

Returns: <string>

Escape regular expression control characters

Example:

escapeRegExp('/path/to/res?search=this.that');

newEscapedRegExp(s)

Returns: <RegExp>

Generate escaped regular expression

addTrailingSlash(s)

Returns: <string>

Add trailing slash at the end if there isn't one

stripTrailingSlash(s)

Returns: <string>

Remove trailing slash from string

dirname(filePath)

Returns: <string>

Get directory name with trailing slash from path

capitalize(s)

Returns: <string>

Capitalize string

between(s, prefix, suffix)

Returns: <string>

Extract substring between prefix and suffix

removeBOM(s)

Returns: <string>

Remove UTF-8 BOM

arrayRegExp(items)

Returns: <RegExp>

Generate RegExp from array with '*' wildcards

Example:

['/css/*', '/index.html'];

section(s, separator)

Returns: <string[]>

Split string by the first occurrence of separator

Example:

rsection('All you need is JavaScript', 'is');

Result:

['All you need ', ' JavaScript'];

rsection(s, separator)

Returns: <string[]>

Split string by the last occurrence of separator

Example:

rsection('All you need is JavaScript', 'a');

Result:

['All you need is Jav', 'Script'];

split(s[, separator[, limit]])

  • s: <string>
  • separator: <string> (optional), default: ','
  • limit: <number> (optional), default: -1, max length of result array

Returns: <string[]>

Split string by multiple occurrence of separator

Example:

split('a,b,c,d');

Result:

['a', 'b', 'c', 'd'];

Example:

split('a,b,c,d', ',', 2);

Result:

['a', 'b'];

rsplit(s[, separator[, limit]])

  • s: <string>
  • separator: <string> (optional), default: ','
  • limit: <number> (optional), default: -1, max length of result array

Returns: <string[]>

Split string by multiple occurrences of separator

Example:

split('a,b,c,d', ',', 2);

Result:

['c', 'd'];

normalizeEmail(email)

  • email: <string> email address to normalize

Returns: <string> normalized email address

Normalize email address according to OWASP recommendations

isTimeEqual(time1, time2)

Returns: <boolean>

Compare time1 and time2

Example:

isTimeEqual(sinceTime, buffer.stats.mtime);

nowDate([date])

  • date: <Date> (optional), default: new Date()

Returns: <string>

Get current date in YYYY-MM-DD format

nowDateTime([date])

  • date: <Date> (optional), default: new Date()

Returns: <string>

Get current date in YYYY-MM-DD hh:mm format

class Uint64

Uint64.add(a, b)

Uint64.and(a, b)

Uint64.cmp(a, b)

Uint64.div(a, b)

Uint64.mod(a, b)

Uint64.mult(a, b)

Uint64.not(a)

Uint64.or(a, b)

Uint64.shiftLeft(a, b)

Uint64.shiftRight(a, b)

Uint64.sub(a, b)

Uint64.xor(a, b)

Uint64.prototype.constructor(value)

Uint64.prototype.add(b)

Uint64.prototype.and(b)

Uint64.prototype.dec()

Uint64.prototype.inc()

Uint64.prototype.not()

Uint64.prototype.or(b)

Uint64.prototype.shiftLeft(b)

Uint64.prototype.shiftRight(b)

Uint64.prototype.sub(b)

Uint64.prototype.toJSON()

Uint64.prototype.toPostgres()

Uint64.prototype.toString(radix = 10)

Uint64.prototype.toUint32()

Uint64.prototype.xor(b)

duration(s)

Returns: <number> milliseconds

Parse duration to seconds

Example:

duration('1d 10h 7m 13s');

durationToString(n)

Returns: <string>

Convert integer duration to string

bytesToSize(bytes)

Returns: <string>

Convert integer to string, representing data size in Kb, Mb, Gb, and Tb

sizeToBytes(size)

Returns: <number>

Convert string with data size to integer

safe(fn)

Returns: <Function> function(...args), wrapped with try/catch interception

  • args: <Array> arguments to be passed to wrapped function

Make function raise-safe

captureMaxStack()

callerFilename(depth = 0, stack = null)

callerFilepath(depth = 0, stack = null)

  • depth: <number>|<RegExp> initial stack slice or filter regular expression, 0 by default.
  • stack: <string> stack string, optional

Try to detect the filepath of a caller of this function.

Contributors

See github for full contributors list

common's People

Contributors

aqrln avatar belochub avatar dzyubspirit avatar ivan-tymoshenko avatar ivhc avatar juliagerasymenko avatar lundibundi avatar mille-nium avatar nechaido avatar semenchenkovitaliy avatar tshemsedinov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

common's Issues

Chain composition

@DzyubSpirit I think to compose chain we can use following syntax:

const composedChain = compose().filter(x => x > 0).map(x => x * 2).map(x => ++x);

And then use it:

const result = composedChain(data);

It will be equivalent for expression/superposition:

const result = data.filter(x => x > 0).map(x => x * 2).map(x => ++x);

But unknown data.
We can also do it easier:

const composedChain = data => data.filter(x => x > 0).map(x => x * 2).map(x => ++x);
const result = composedChain(data);

But in case of simple compose we also can do as lambda:

const composedFunc = x => f1(f2(x));

But function compose gives us flexibility and unification.
So chain composition may give us something interesting.
Need more examples, I think.

Curry alternative implementation

Now we have curry = (fn, ...args) => fn.bind(null, ...args);
Maybe it's better curry = (fn, ...a1) => (...a2) => fn(...a1, ...a2);
Tests needed

Generate docs

As a quick solution use autogeneration from function signature parser and publish to README.md

Implement curry

I think there are many occasions when bind is used with null first argument. Does it need implementation? And what file should it place in?

Functional functions

Add common functions for functional programming:

  • zip
  • zipWith
  • curryTwice
  • maybe
  • compose
  • applyArgs
  • replicate
  • omap
    identity

P.S. I will be glad if anybody add points, edit or comment on that list

Implement zip and zipWith functions

const result = api.common.zip(
  [1, 2, 3, 4, 5],
  ['one', 'two', 'three', 'four', 'five']
  ['ะพะดะธะฝ', 'ะดะฒะฐ', 'ั‚ั€ะธ', 'ั‡ะพั‚ะธั€ะธ', 'ะฟ\'ัั‚ัŒ'],
);
/*
result: [ 
  [1, 'one', 'ะพะดะธะฝ'], 
  [2, 'two', 'ะดะฒะฐ'], 
  [3, 'three', 'ั‚ั€ะธ'], 
  [4, 'four', 'ั‡ะพั‚ะธั€ะธ'], 
  [5, 'five', 'ะฟ\'ัั‚ัŒ'] 
]
*/
const result = api.common.zipWith(
  ([num, eng, rus]) => ({ num, eng, rus }),
  [1, 2, 3, 4, 5],
  ['one', 'two', 'three', 'four', 'five'],
  ['ะพะดะธะฝ', 'ะดะฒะฐ', 'ั‚ั€ะธ', 'ั‡ะพั‚ะธั€ะธ', 'ะฟ\'ัั‚ัŒ'],
);
/*
result: [ 
  { num: 1, eng: 'one', rus: 'ะพะดะธะฝ' }, 
  { num: 2, eng: 'two', rus: 'ะดะฒะฐ' }, 
  { num: 3, eng: 'three', rus: 'ั‚ั€ะธ' },
  { num: 4, eng: 'four', rus: 'ั‡ะพั‚ะธั€ะธ' }, 
  { num: 5, eng: 'five', rus: 'ะฟ\'ัั‚ัŒ' }
 ];
*/ 

Implement curryN function

const concat = (x, y, z, a, b) => (x + y + z + a + b);
const hello = curryN(concat, 2, "hello, ");
const helloWorld = hello(" world!");
helloWorld();
// prints "hello, world!undefinedundefinedundefined"
const helloWorld2 = curryN(concat, 3, "hello, ", "world!");
const helloWorld2WithPlace = helloWorld2(" Kyiv, Ukraine");
const hellowWorld2WithPlaceAndTime = helloWorld2WithPlace(" in 1990");
helloWorld2WithPlaceAndTime(" by <personname>");
// prints "hello, world! Kyiv, Ukraine in 1990 by <personname>"

Implement emitter

const from = common.emitter();
const to = common.emitter();

// Forward all events
from.forward(to);

// Forward event by name
from.forward(to, 'eventName');

// Forward multiple events
from.forward(to, ['eventName1', 'eventName2']);

// Forward events and rename
from.forward(to, { eventName: 'newEventName' });

// Forward all events
common.forwardEvents(from, to);

// Forward event by name
common.forwardEvents(from, to, 'eventName');

// Forward events and rename
common.forwardEvents(from, to, { eventName: 'newEventName' });

// Forward multiple events
common.forwardEvents(from, to, ['eventName1', 'eventName2']);

Implement curryTwice

curryTwice transforms function in so way that it then could be execute twice.

const curryTwice = api.common.curryTwice;
const asAsync = api.metasync.asAsync;
const sum = (x, y) => (x + y);
const result = curryTwice(sum)(4)(5);
// result: 9
const dur1 = asAsync(fs.readFile, 'config1.json').fmap(JSON.parse).fmap(x => x.duration);
const dur2 = asAsync(fs.readFile, 'config2.json').fmap(JSON.parse).fmap(x => x.duration);
const result2 = api.metasync.asAsync(curryTwice(sum)).ap(dur1).ap(dur2);
result2(console.log);
// prints sum of two durations

Rewrite lib/units without regexp parsing

Submodule lib/units uses regular expressions to parse duration intervals and file size. It would be great to rewrite it using simple string operations. I created branch: rewrite-units-parsing and changed constants: DURATION_UNITS and UNIT_SIZES. Next step is to rewrite functions:

  • duration
  • sizeToBytes

If you want to reimplement mentioned functions please contact me and I'll assign you to this task.

Implement Haskell lens package functions

Working with GlobalStorage means working with nested objects with deeply nested structures. Haskell solution for that is lenses.
There is rambda-lens implementation for javascript. It's fully functional and so performance is only okay using with immutable-js.
But we can rewrite functions using functionality and mutability for best results.

There are many functions in the lens so I give only a few examples in this issue. There is also an article about using rambda-lens.

Data:

const users = [{
  id: 3,
  name: 'Charles Bronson',
  addresses: [{
    street: '99 Walnut Dr.',
    zip: '04821',
  }, {
    street: '2321 Crane Way',
    zip: '08082',
  }],
}, {
  id: 5,
  name: 'Mr. Ambassador',
  addresses: [{
    street: '2050 Bamako Place',
    zip: '20521-2050',
  }, {
    street: '7100 Athens Place',
    zip: '20521-7100',
  }],
}];

Standard way:

users.forEach((_, i, arr) =>
  arr[i]['addresses'].forEach((_, i, arr) =>
    arr[i]['street'] = '*****'
  )
);

Using lens:

const { set, lensProp, mapped } = require('metarhia-common');
set([mapped, lensProp('addresses'), mapped, lensProp('street')], '*****', users);

Implement splitAt function

splitAt splits array into two parts

const array = [1, 2, 3, 4, 5];
const result = splitAt(3, array);
// result: [[1, 2, 3], [4, 5]]

Implement partial

In /lib/fp.js
Usage:

const func = (a, b, c, d) => (a + b + c + d);
const fn = partial(func, a, b);
fn(c, d);

Rename module

We need shorter and conceptual name for npm. Now npm module name is metarhia-common

Add map,filter, etc. for iterators

I propose to add an Iterator class that has map, filter, etc. functions. Example syntax:

const set = new Set([1, 2, 3, 4]);

const doubledArray = new Iterator(set)
  .map(item => item * 2)
  .fetch();

const ten = new Iterator(set)
  .reduce((previous, current) => previous + current, 0);

new Iterator(set).forEach(item => console.log(item));

Unobvious lib format

IMHO, if we use namespaces - all fuctions from namespacce should be in one file. If we have a need to divide them into few logical parts - we add a corresponding namespace.. It will look like:

lib
|-common.js    // ~~api.common.function()
|-common
  |-data.js    // ~~api.common.data.function()
  |-id.js      // ~~api.common.id.function()

@tshemsedinov @aqrln @belochub what do you think about it?

Broken `git log` output

$ git log --oneline
9d815a5 test: make linting a part of the testing process PR-URL: https://github.com/metarhia/Common/pull/4 * Add `npm run lint` script that can be invoked on its own. * Run linter in the end of `npm test` script if the tests have passed.
7b13f1e lib: code style optimizations PR-URL: https://github.com/metarhia/Common/pull/3
8c4713d lib: optimize object cloning PR-URL: https://github.com/metarhia/Common/pull/1
5e7d7d3 lib: make `clone` abstract again
37f0079 Add required dependencies
6b6544f Fix namespaces export
6f07e7d Add api.common.cache (enhanced Map)
d4ceded Extract api.common from Impress
07bb9b0 Fix exports
e736df5 Library structure
1750b04 Initial commit

@tshemsedinov an empty line after the short commit message is required by Git. Without it, the whole commit description is a short message with newlines treated as spaces.

Implement applyArgs

applyArgs take arguments and returns function which takes function and apply these arguments to it.

const multy = [2, 3, 4, 5].map(x => y => (x * y));
multy.map(applyArgs(4)); // [8, 12, 16, 20]

const asyncFns = [...];
const data = { ... } ;
const callback = (...) => { ... };
asyncFns.map(applyArgs(data, callback));

Asynchronous NOP

We have NOP (no operation) synchronous function common.emptiness but need a NOP for asynchronous callback-last/error-first:

common.nop = (callback) => {
  callback(null);
}

Implement replicate function

Replicate takes array size and value and returns array filled with that value.

api.common.replicate(5, true); // [true, true, true, true, true]

Minimize the build time on CI

I have enabled CI for the repo, but I haven't changed the default settings. Now each PR is built twice: as a push to a branch and as a PR itself. Now we need to consider:

  1. If this repo adopts purely PR-based workflow, we may disable build on pushes completely, and, optionally, schedule nightly builds on master every 24 hours (that's how JSTP is configured).

  2. If the project adopts some mixed workflow when both PRs and direct pushes to master are allowed, like Impress does, then we can leave both "build on pushes" and "build on PRs" settings turned on but whitelist branches to master only. This way all pushes to master and all the PRs will be built.

/cc @tshemsedinov

Time utilities: lib/time

  • Compare nowDate performance with following new Date().toISOString().substring(0, 10)
  • Compare nowDateTime with new Date().toISOString().substring(0, 16).replace('T', ' ')
  • Propose more data and time utilities

One set of tests

We have ./test (using metatests) and ./tests (examples using assert)

Implement omap function

omap behaves the same as map for arrays except index is field name instead array index.

const result = api.common.omap(p => p.side, { 
  vlad: { age: 20, side: 'good' }, 
  dziuba: { age: 20, side: 'evil' }
);
// result: { vlad: 'good', dziuba: 'evil' }

Implement maybe function

maybe is used for transform value if isn't null/undefined and gives default if it is.

const val1 = { duration: 355 };
const val2 = null;
api.common.maybe(config => config.duration, 10, val1); // 355
api.common.maybe(config => config.duration, 10, val2); // 10

Remove lib/require

safeRequire and requireEither can't be imported from npm packet because npm will not see dependencies.

Implement compose function

compose performs mathematical function composition

const fns = [x => (x + 2), x => (x * 4), x => (x / 5)];
api.common.compose(...fns)(4); // 5.8

Implement HashMap

We need quick implementation. Also pleas add links to articles about performance problems or comparison tests. We may prepare js prototype based on Typed Arrays, then prepare speed/performance tests. After that we may implement C++ or Rust implementation for node.js

Implement fullCurry

For functions with static arguments count can be implemented fullCurry which can curry function until all arguments will be given.

const callback = ...;
fullCurry(fs.readFile)('input.txt')({ encoding: 'utf-8' })(callback);
fullCurry(fs.readFile, 'input.txt')({ encoding: 'utf-8' }, callback);
const readInputUtf8 = fullCurry(fs.readFile, 'input.txt')({ encoding: 'utf-8' });

Implement safe wrapper

// Examples:

const safeRequire = common.safe(require);
const [err, name] = safeRequire('./name');

const parser = common.safe(JSON.parse);
const [err, data] = parser('{a:}');

Write more tests

  • lib/callbacks
  • lib/data
  • lib/fp
  • lib/id
  • lib/math
  • lib/network
  • lib/oop
  • lib/sort
  • lib/strings
  • lib/time
  • lib/units
  • lib/utilities

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.