npm package: @flk/support-javascript
Description: List of helpful functions in Strings, Objects, Arrays, Numbers and others.
Latest version: 1.3.0

# FLK Support Javascript  

FLK support Javascript is a list of functions and methods to robust your application.

# Installation

This package is a standalone package from [Falak JS Framework](https://github.com/falakjs/falak), so you can use it in your application.

`npm install flk-support-javascript`

> If you're using [Falak JS Framework](https://github.com/falakjs/falak), By default this package is installed automatically so no need to install it.

# Important Note
This package will use a [Monkey Patch](https://mentoor.io/en/posts/what-is-monkey-patch/10) approach to override some existing code like [string methods](#string).


# List of helpers

- [Array](#array)
- [Number](#number)
- [Object](#object)
- [Regex](#Regex)
- [String](#String)


# Array

A very useful methods to manipulate arrays in `Javascript`.

- [chunk](#array-chunk)
- [clone](#array-clone)
- [get](#array-get)
- [pushOnce](#array-pushOnce)
- [random](#array-random)
- [remove](#array-remove)
- [removeAll](#array-remove-all)
- [reset](#array-reset)


## Array Chunk

`Array.chunk(array: array, size: number): array`

Chunks an array into arrays with `size` elements.

### Example

```js
let numbers = [1, 2, 3, 4, 5, 6];

let chunkedNumbers = Array.chunk(numbers, 2); // it will split it to array that contains three elements

// output
[
    [1, 2],
    [3, 4],
    [4, 6]
]
```

## Array Clone

`Array.clone(array: array): array`

Clone the array to new array with same elements.

This is a useful if you want to lose the reference of the array.

### Example

```js
// when you assign the array to another variable

let names = ['Hasan', 'Sarah'];

let newNames = names;

newNames.push('Hendawy');

console.log(names); // ['Hasan', 'Sarah', 'Hendawy']
console.log(newNames); // ['Hasan', 'Sarah', 'Hendawy']

// using the clone method

let anotherNames = ['John', 'Doe'];

let newAnotherNames = Array.clone(names);

newAnotherNames.push('Smith');

console.log(anotherNames); // ['John', 'Doe']
console.log(newAnotherNames); // ['John', 'Doe', 'Smith']
```

## Array End

`Array.end(array: array): any`

Get the last element of the array `without removing it`.

### Example

```js
let names = ['Hasan', 'Sarah'];

let lastName = Array.end(names);

console.log(lastName); // Sarah
// names array doesn't lose the last element 
console.log(names); // ['Hasan', 'Sarah']
```

## Array get

`Array.get(array: array, callback: Function): any`

Get the first matched element of array for the given callback function.

> This method is too much like the [filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) but this returns only one element instead. 

If no matching elements, null returned.

### Example

```js
let users = [{
    id: 1,
    name: 'Hasan',
}, {
    id: 5231,
    name: 'Hendawy',
}, {
    id: 691,
    name: 'John',
}, {
    id: 9121,
    name: 'Hasan',
}];

// get the first user that his name is Hasan

let user = Array.get(users, user => user.name == 'Hasam'); // {id: 1, name: 'Hasan'}
```

## Array pushOnce

`Array.pushOnce(array: array, value: any): array`

Push the given element to array, if and only if the element doesn't exist in the array.

### Example

```js
let numbers = [1, 3, 5, 6];

let anotherNumbers = Array.pushOnce(numbers, 2); // [1, 3, 5, 6, 2] Element added
anotherNumbers = Array.pushOnce(anotherNumbers, 1); // [1, 3, 5, 6, 2] Element exists, nothing added
```

## Array random

`Array.random(array: array): any`

Get random element from the array.

### Example

```js
let numbers = [1, 3, 5, 6];

let randomNumber = Array.random(numbers); 
```

## Array remove

`Array.remove(array: array, value: any): array`

Remove `the first matched` value from array.

### Example
```js
let numbers = [1, 3, 5, 6];

let newNumbers = Array.remove(numbers, 3); // [1, 5, 6]
```

## Array remove all

`Array.removeAll(array: array, value: any): array`

Remove `all matched` values from array.

### Example
```js
let numbers = [1, 3, 5, 6, 1, 2, 4, 1, 12];

let newNumbers = Array.removeAll(numbers, 1); // [3, 5, 6, 2, 4, 12]
```

## Array reset

`Array.reset(array: array): array`

Reset the array for proper indexing.  

### Example
```js
let numbers = [1, 2, 3, 4];

delete numbers[1];

console.log(numbers); 
// output
0: 1
2: 3
3: 4
length: 4

console.log(Array.reset(numbers)); 
// output
0: 1
1: 3
2: 4
length: 3
```

# Number

A very useful methods to manipulate arrays in `Number`.

- [format](#number-format)
- [round](#number-round)

# Number Format
`Number.format(): string`

Format the number to a `money-like` format. 

## Example

```js

let salary = 134512;

let formatedSalary = salary.format(); // 134,512
```

# Number round
`Number.round(precision: int): number`

Round the number up

## Example

```js

let salary = 12341.5121;

let formatedSalary = salary.round(2); // 12340.51
```

# Object

A very useful methods to manipulate arrays in `Object`.

- [clone](#object-clone)
- [get](#object-get)
- [key](#object-key)
- [match](#object-match)
- [set](#object-set)
- [size](#object-size)
- [sort](#object-sort)


## Object Clone

`Object.clone(object: Object): Object`

Clone the Object to new Object with same elements.

This is a useful if you want to lose the reference of the Object.

### Example

```js
// when you assign the object to another variable

let user = {
    id: 1,
    name: 'Hasan'
};

let adminUser = user;

adminUser.email = 'hassanzohdy@gmail.com';

console.log(user); // {id: 1, name: 'Hasan', email: 'hassanzohdy@gmail.com'}
console.log(adminUser); // {id: 1, name: 'Hasan', email: 'hassanzohdy@gmail.com'}

// using the clone method

let anotherUser = {
    id: 12,
    name: 'John'
};

let newAnotherUser = Object.clone(anotherUser);

newAnotherUser.email = 'john@doe.com';

console.log(anotherUser); // {id: 12, name: 'John'}
console.log(newAnotherUser); // {id: 12, name: 'John', email: 'john@doe.com'}
```

## Object get

`Object.get(object: Object, key: string, defaultValue = null: any): any`

Get a value from the given object for the given `dot.notation` key. 

> This will be probably your best friend method to work with.


This method differs from the nested object properties that if the nest property doesn't exist, the Javascript Engine won't complain `call x of undefined`.

### Example

```js
let user = {
    id: 1,
    name: 'Hasan',
    address: {
        building: {
            number: 12,
            floor: 3,
            apartment: 36
        },
    },
};

// get the user apartment no.

let apartmentNumber = user.address.building.apartment; // 36

// but what if the user doesn't have an `address` property?
let anotherUser = {
    id: 321,
    name: 'Hendawy',
};

let hendawyApartmentNumber = anotherUser.address.building.apartment; // Error: call building property of undefined.

// now let's try our method 
let newHendawyApartmentNumber = Object.get(anotherUser, 'address.building.apartment'); // null returned as the building property doesn't exist on the address, but no errors are triggered.

// we can also return a default value if the `dot.notation` property doesn't exist

let newHendawyApartmentNumberWithDefaultValue = Object.get(anotherUser, 'address.building.apartment', 120); // 120

// back to the first user
// if the property exists, it will work as well.
let userAddressUsingGetMethod = Object.get(user, 'address.building.apartment'); // 36
```

This method can deep dive to unlimited number of nested objects, so you're ready to go with it.

## Object key

`Object.key(object: Object, value: any): any`

Get the key of the value from the given object. 

### Example

```js
let user = {
    id: 1,
    name: 'Hasan'
};

let key = Object.key(user, 'Hasan'); // name
let anotherKey = Object.key(user, 1); //id
// if the value doesn't exist in the object, a null is returned instead.
let nullKey = Object.key(user, 'hassanzohdy@gmail.com'); // null
```

## Object match

`Object.match(...objects: Object): boolean`

Check if the passed objects are matched.

### Example

```js
let objectA = {
    name: 'A',
    key: 'Group',
};

let objectB = {
    name: 'B',
    key: 'Group'
};

let isMatchedObjects = Object.match(objectA, objectB); // false

let objectC = {
    name: 'A',
    key: 'Group',
};

let isMatchedObjectsSecondTime = Object.match(objectA, objectC); // true
```


## Object set

`Object.set(object: Object, key: string, value: any): object`

Set a value in the given object for the given `dot.notation` key. 

It works exactly the same as [Object.get](#object-get) but in setting instead of getting keys. 

### Example

```js
let user = {
    id: 1,
    name: 'Hasan',
};


Object.set(user, 'status', 'Active');

console.log(user); // {id: 1, name: 'Hasan', status: 'Active'}

Object.set(user, 'address.building.number', 12);

console.log(user); // output
/*
{
    id: 1, 
    name: 'Hasan', 
    status: 'Active', 
    address: {
        building: {
            number: 12
        }
    }
}
*/
```

## Object size

`Object.size(object: Object): number`

Get the size of the object, total properties inside it.

> This method calculates only the first level of properties not all nested properties.

### Example

```js
let user = {
    id: 1,
    name: 'Hasan',
};

let objectSize = Object.size(user); // 2
```

## Object sort

`Object.sort(object: Object): object`

Sort the given object keys `Alphabetically` and return the new sorted object.

### Example

```js
let user = {
    id: 1,
    name: 'Hasan',
    address: 'Some Address', 
};

let sortedObject = Object.sort(user); // {address: 'Some Address', id: 1, name: 'Hasan'}
```

# Regex

A very useful methods to manipulate arrays in `regex`.

- [escape](#regex-escape)

# Regex escape

`RegExp.escape(string: string): string`

Escape any character that should be escaped if the string is passed to `new RegExp` statement.

### Example

```js


let searchKeywords = 'hello+world';


let string = 'hello+world';

// the normal way.
echo(string.match(new RegExp(`^${searchKeywords}$`))); // null

// using the escape method.
echo(string.match(new RegExp(`^${RegExp.escape(searchKeywords)}$`))); // ["hello+world", index: 0, input: "hello+world", groups: undefined]
```

# String

A very useful methods to manipulate arrays in `String`.

> All of the string methods are implementing [Monkey Patch](https://mentoor.io/en/posts/what-is-monkey-patch/10).

- [capitalize](#string-capitalize)
- [format](#string-format)
- [ltrim](#string-ltrim)
- [readMoreChars](#string-readMoreChars)
- [removeFirst](#string-removeFirst)
- [removeLast](#string-removeLast)
- [repeatsOf](#string-repeatsOf)
- [replaceAll](#string-replaceAll)
- [replaceFirst](#string-replaceFirst)
- [replaceLast](#string-replaceLast)
- [rtrim](#string-rtrim)
- [sprintf](#string-sprintf)
- [toCamelCase](#string-toCamelCase)
- [toInputName](#string-toInputName)
- [toSnakeCase](#string-toSnakeCase)
- [toStudlyCase](#string-toStudlyCase)
- [trim](#string-trim)
- [ucfirst](#string-ucfirst)
- [vsprintf](#string-vsprintf)

# String capitalize

`String.prototype.capitalize(): string`

Capitalize each word in the string.

### Example

```js

let greeting = 'hello world';

console.log(greeting.capitalize()); // Hello World
```


# String format

`String.prototype.format(): string`

Format the string if it contains only integers or floats to a money format.

### Example

```js

let salary = '25332';

console.log(salary.format()); // 25,332
```


# String ltrim

`String.prototype.ltrim(needle: string = ' '): string`

Remove from the beginning of the string the given needle  

### Example

```js

let name = 'Hasan';

console.log(name.ltrim('H')); // asan

// removes the spaces from the beginning of the string if no needle passed to the method.
let stringWithSpace = ' ok'; // length >> 3
console.log(stringWithSpace.ltrim()); // length >> 2
```

# String readMoreChars

`String.prototype.readMoreChars(length: string, readMoreDots = '...': string): string`

Cut string for the given length and append ... if string is larger than the given length

### Example

```js

let tip = 'Do you know that implementing some existing libraries/plugins with yourself will improve your problem solving skills?';

let cutTip = tip.readMoreChars(10); 

console.log(cutTip); // Do you kno....
```

# String removeFirst

`String.prototype.removeFirst(needle: string): string`

Remove the first matched string to the given needle from current string.

### Example
```js

let name = 'Hasan';

console.log(name.removeFirst('a')); // Hsan
```


# String removeLast

`String.prototype.removeLast(needle: string): string`

Remove the last matched string to the given needle from current string.

### Example
```js

let name = 'Hasan';

console.log(name.removeLast('a')); // Hasn
```

# String repeatsOf

`String.prototype.repeatsOf(needle: string, caseSensitive = true: boolean): string`

Count the occurrence of the given needle 

### Example
```js

let name = 'Hasan';

console.log(name.repeatsOf('a')); // 2
console.log(name.repeatsOf('H')); // 1
console.log(name.repeatsOf('h')); // 0 case sensitive
console.log(name.repeatsOf('h', false)); // 1 case insensitive
```

# String replaceAll

`String.prototype.replaceAll(searchText: string|regex): string`

Replace `all the matched` string for the given search text. 

### Example
```js

let name = 'Hasan';

console.log(name.replaceAll('a', 'o')); // Hoson
```

# String replaceFirst

`String.prototype.replaceAll(searchText: string|regex): string`

Replace `the first` matched string for the given search text. 

### Example
```js

let name = 'Hasan';

console.log(name.replaceFirst('a', 'o')); // Hosan
```

# String replaceLast

`String.prototype.replaceLast(searchText: string|regex): string`

Replace `the last` matched string for the given search text. 

### Example
```js

let name = 'Hasan';

console.log(name.replaceLast('a', 'o')); // Hason
```

# String rtrim

`String.prototype.rtrim(needle: string = ' '): string`

Remove from the end of the string the given needle  

### Example

```js

let name = 'Hasan';

console.log(name.rtrim('n')); // Hasa

// removes the spaces from the end of the string if no needle passed to the method.
let stringWithSpace = 'ok '; // length >> 3
console.log(stringWithSpace.rtrim()); // length >> 2
```

# String sprintf

`String.prototype.rtrim(...replacements: any[]'): string`

Returns a string produced according to the formatting string 

> This is a very useful method if you're dealing with translations.

### Example

```js

let requiredValidation = '%s is required'; 

console.log(requiredValidation.sprintf('Password')); // Password is required
```

Current supported formats are for strings and integers.

For example if we want to change a number instead of a string:

```js

let totalItems = '%d items in total'; 

console.log(totalItems.sprintf(12)); // 12 items in total
```

You can mix and add as much as you want with strings and integers.


```js

let lengthValidation = '%s should be between %d and %d'; 

console.log(lengthValidation.sprintf('Password', 8, 12)); // Password should be between 8 and 12
```


# String toCamelCase

`String.prototype.toCamelCase(): string`

Convert a string to a `camel case` string. 

### Example

```js
// with spaces
console.log('hello world'.toCamelCase()); // helloWorld
// with dashes
console.log('hello-world'.toCamelCase()); // helloWorld
// with underscores
console.log('hello_world'.toCamelCase()); // helloWorld
// if first letter is capitalized, it will be converted to lower case
console.log('Hello_world'.toCamelCase()); // helloWorld
```

# String toInputName

`String.prototype.toInputName(): string`

Convert a dot notation string to a proper formatted input name. 

This will save you from the too many brackets when you deal with 

### Example

```js

let EnglishDescriptionName = 'description.en';
let ArabicDescriptionName = 'description.ar';

console.log(EnglishDescriptionName.toInputName()) ; // description[en]
console.log(ArabicDescriptionName.toInputName()) ; // description[ar]

// a more deeper input names
for (let i = 0; i < 4; i++) {
    let attributeNameEnglish = `attributes.${i}.name.en`;
    console.log(attributeNameEnglish.toInputName()); // attributes[0][name][en]

    let attributeNameArabic = `attributes.${i}.name.ar`;
    console.log(attributeNameArabic.toInputName()); // attributes[0][name][ar]
}
```

# String toSnakeCase

`String.prototype.toSnakeCase(lowerAll = true: boolean): string`

Convert a string to a `snake case` string. 

By default, if any camelCase string is detected, it will be converted to `snake_case`, if you want to convert it to `snake_Case` to keep the capital letters as it is, pass `false` to the method to keep it as original.

### Example

```js
// with spaces
console.log('hello world'.toSnakeCase()); // hello_world
// with dashes
console.log('hello-world'.toSnakeCase()); // hello_world
// with camelCases
console.log('helloWorld'.toSnakeCase()); // hello_world
// with camelCase but keep capital letters as it is
console.log('helloWorld'.toSnakeCase(false)); // hello_World
```


# String toStudlyCase

`String.prototype.toStudlyCase(): string`

Convert a string to a `StudlyCase` string. 

### Example

```js
// with spaces
console.log('hello world'.toStudlyCase()); // HelloWorld
// with dashes
console.log('hello-world'.toStudlyCase()); // HelloWorld
// with snake case
console.log('hello_world'.toStudlyCase()); // HelloWorld
// with camel case
console.log('helloWorld'.toStudlyCase()); // HelloWorld
```


# String trim

`String.prototype.trim(needle: string = ' '): string`

Remove from `the beginning` and `the end` of the string the given needle.

### Example

```js

let name = 'Hasan';

console.log(name.trim('H')); // asan

let route = '/home/';

console.log(route.trim('/')); // home

// trimming whitespaces

let text = '  hello world  '; // two spaces at the beginning and the end with length: 15 
console.log(text.trim()); // length: 11 
```

# String ucfirst

`String.prototype.ucfirst(): string`

Capitalize only `the first word` in the string.

### Example

```js

let greeting = 'hello world';

console.log(greeting.ucfirst()); // Hello world
```

# String vsprintf

`String.prototype.rtrim(replacements: array'): string`

Returns a string produced according to the formatting string 

Works exactly like [String.sprintf](#string-sprintf) but instead it accepts an array of replacements. 

### Example

```js

let lengthValidation = '%s should be between %d and %d'; 

console.log(lengthValidation.vsprintf(['Password', 8, 12])); // Password should be between 8 and 12
```