npm package: @oc-tech/lodash-ext
Description: Enhances lodash experience catering for real world functionality
Author: Desmond O'Leary
Latest version: 0.0.6

# Lodash Extensions
---

### Usage

> The version of your node.js should be greater than v12

```bash
git clone git@github.com:omnitech-solutions/lodash-ext.git YOURFOLDERNAME
cd YOURFOLDERNAME

# Run npm install and write your library name when asked. That's all!
yarn install
```

### Features

 - Zero-setup. After running `npm install` things will setup for you :wink:
 - **[RollupJS](https://rollupjs.org/)** for multiple optimized bundles following the [standard convention](http://2ality.com/2017/04/setting-up-multi-platform-packages.html) and [Tree-shaking](https://alexjoverm.github.io/2017/03/06/Tree-shaking-with-Webpack-2-TypeScript-and-Babel/)
 - Tests, coverage and interactive watch mode using **[Jest](http://facebook.github.io/jest/)**
 - **Docs automatic generation and deployment** to `gh-pages`, using **[TypeDoc](http://typedoc.org/)**
 - Automatic types `(*.d.ts)` file generation
 - (Optional) **Automatic releases and changelog**, using [standard-version](https://github.com/conventional-changelog/standard-version#readme), [Commitizen](https://github.com/commitizen/cz-cli), [Conventional changelog](https://github.com/conventional-changelog/conventional-changelog) and [Husky](https://github.com/typicode/husky) (for the git hooks)
 - Deploy your docs to github pages via gh-pages branch

### Importing library

You can import the generated bundle to use the whole library generated by this starter:

### NPM scripts

 - `npm lint`: Eslint code
 - `npm lint:fix`: Eslint code and try to fix problems
 - `npm start`: Realtime complie code
 - `npm run docs`: Generate type documents
 - `npm run build`: Build ths dist products
 - `npm run release`: The same as `npm run release:patch`
 - `npm run release:patch`: Automatically upgrade patch versioin and update CHANGELOG.md
 - `npm run release:minor`: Automatically upgrade minor versioin and update CHANGELOG.md
 - `npm run release:major`: Automatically upgrade major versioin and update CHANGELOG.md
 - `npm run test`: Run test suite via jest with code coverage
 - `npm run test:watch`: Run test suite in [interactive watch mode](http://facebook.github.io/jest/docs/cli.html#watch)
 - `npm run test:prod`: Run linting and generate coverage
 - `npm run deploy`: Clean docs directory and rebuild docs pages

### Git Hooks

There is already set a `precommit` hook for formatting your code with Eslint and Commitlint :nail_care:

By default, there are two disabled git hooks. They're set up when you run the `npm i` script. They make sure:
 - You follow a [conventional commit message](https://github.com/conventional-changelog/conventional-changelog)

## Usage

### "Array" Methods

#### omit

> removes matching values from array

```ts
omit([1, 2, 3, 4], [2, 4]) // => [1, 3]
```

#### omitIndex

> removes value at given index

```ts
omitIndex([1, 2, 3, 4], 2) // => [1, 2, 4]
```


### "Lang" Methods

#### isBlank

> Checks if value is classified as a boolean primitive or object. handles more scenarios

```ts
isBlank('') // => true
isBlank('   ') // => true
isBlank(null) // => true
isBlank({}) // => true
isBlank(0) // => true

isBlank('1') // => false
isBlank('1') // => false
isBlank({a: 1}) // => false
isBlank(1) // => false
```

#### isDeepEquals

> Performs a deep comparison between two values and returns true if they are identical

```ts
const a = [{ one: { car: 1, vehicle: { truck: 3 } }, two: 2 }];
const b = cloneDeep(a);

isDeepEquals(a, b) // => true

a[0].one.vehicle = 4
isDeepEquals(a, b) // => false
```

#### isDeepDifferent

> Performs a deep comparison between two values and returns true if they are different

```ts
const a = [{ one: { car: 1, vehicle: { truck: 3 } }, two: 2 }];
const b = cloneDeep(a);

isDeepDifferent(a, b) // => false

a[0].one.vehicle = 4
isDeepDifferent(a, b) // => true
```

#### isEmail

> returns true if value is a valid email format

```ts
isEmail('email@domain.com') // => true
isEmail('email@d.ca') // => true

isEmail('not-an-email') // => false
isEmail('email@domain.c') // => false
```

#### isPresent

> Direct opposite of `isBlank`

```ts
isPresent('') // => false
isPresent('   ') // => false
isPresent(null) // => false
isPresent({}) // => false
isPresent(0) // => false

isPresent('1') // => true
isPresent('1') // => true
isPresent({a: 1}) // => true
isPresent(1) // => true
```

#### isUrl

> returns true if value is a valid url

```ts
isUrl('http://a.b.ca') // => true
isUrl('https://a.b.ca') // => true

isUrl('https://a.b.c') // => false
isUrl('www.google.ca') // => false

```

#### pickIfHasPaths

> returns picked object if at least one path is found in given obj

```ts
pickIfHasPaths({ a: 1, b: 2 }, ['a']) // => { a: 1 }
pickIfHasPaths({ a: 1, b: 2 }, ['c']) // => { a: 1, b: 2 } # original obj
pickIfHasPaths({ a: 1, b: 2 }, []) // => { a: 1, b: 2 } # original obj
```

#### toEnum

> Supports filling complex arrays

```ts
toEnum({ rowCount: 3 }) // => [0, 1, 2]
toEnum(
  {
    rowCount: 3,
    callback: (rowIndex) => ({ rowIndex })
  }
) // => [{ rowIndex: 0 }, { rowIndex: 1 }, { rowIndex: 2 }]
toEnum(
  // @ts-ignore
  { rowCount: 3, columnCount: 2 }
) // => [[[0, 0, 0], [0, 1, 1]],[[1, 0, 2],[1, 1, 3]],[[2, 0, 4],[2, 1, 5]]]

// supports returning empty arrays via `emptyColumn` option
toEnum(
  // @ts-ignore
  { rowCount: 3, columnCount: 2, emptyColumn: true } 
) // => [[[], []],[[], []],[[], []]]
```

#### toMatrix

> Supports filling two-dimensional arrays

```ts
toMatrix(3, 2) // => [[[0, 0, 0],[0, 1, 1]],[[1, 0, 2],[1, 1, 3]],[[2, 0, 4],[2, 1, 5]]]

// supports functions
toMatrix(1, 4, ({ rowIndex, columnIndex, index }) => ({
  rowIndex,
  columnIndex,
  index
})) // => [{ rowIndex: 0, columnIndex: 0, index: 0 },{ rowIndex: 0, columnIndex: 1, index: 1 },{ rowIndex: 0, columnIndex: 2, index: 2 },{ rowIndex: 0, columnIndex: 3, index: 3 }]
```

#### stripNonNumericCharacters

> removes non-numeric characters from string

```ts
stripNonNumericCharacters('1.333') // => '1.333'
stripNonNumericCharacters('1.33ab3') // => '1.333'
stripNonNumericCharacters('1,000,000') // => '1000000'
```

#### toBoolean

> Converts value to boolean

```ts
toBoolean('true') // => true
toBoolean('  true  ') // => true
toBoolean(true) // => true
toBoolean('yes') // => true
toBoolean('1') // => true

toBoolean('0') // => false
toBoolean('no') // => false
toBoolean('   false   ') // => false
toBoolean(false) // => false
toBoolean(undefined) // => false
toBoolean(null) // => false
```

#### toNumber

> Converts value to a number. Handles extra scenarios than base.

```ts
toNumber('250000') // => 250000.0
toNumber('$250,000') // => 250000.0
toNumber('$250,000.00') // => 250000.0
toNumber('£250,000.00') // => 250000.0
toNumber('  true  ') // => 0
toNumber('true') // => 0
toNumber('250000') // => 250000.0
toNumber(true) // => 1
toNumber('false') // => 0
toNumber('  false  ') // => 0
toNumber('adsklj') // => 0
toNumber(undefined) // => 0
toNumber({}) // => NaN
toNumber([]) // => 0
```

### "Number" Methods

#### convertNumericShortcuts

> converts shorthand numeric strings to number

```ts
convertNumericShortcuts('1k') // => 1e3
convertNumericShortcuts('1,100k') // => 11e5
convertNumericShortcuts('1.5m3232.56') // => 15000003232.56
convertNumericShortcuts('1b') // => 1e9
convertNumericShortcuts('1t') // => 1e12
```

#### currencyFormatter

> formats number string to currency format

```ts
currencyFormatter('84156.68') // => $84,156.68
currencyFormatter('84156.68', 'GBP') // => '£84,156.68'
currencyFormatter('84156.105', 'KWD') // => 'KD 84,156.105'
```

#### currencyNormalizer

> normalizes currency to help ensure compatibility across multiple formats

```ts
currencyNormalizer('12345') // => '12345.0'
currencyNormalizer('1,234.5678') // => '1234.5678'
```

#### currencyToBigDecimal

> converts currency string to bigdecimal

```ts
currencyToBigDecimal({ currencyAmount: '$1,000,000.56999' }) // => 1000000.56
```

#### currencyToBigDecimal

> converts currency string to bigdecimal

```ts
normalizeCurrencyWithPrecision('84156.68') // => '84156.68'
normalizeCurrencyWithPrecision('84156.689') // => '84156.68'
```

#### removeUnsupportedCurrencyCharacters

> removes non-numeric values from currency string

```ts
removeUnsupportedCurrencyCharacters('$ 1,000.50') // => '1000.50'
removeUnsupportedCurrencyCharacters('KD 20,000.00') // => '20000.00'
```

#### stripThousandSeparators

> strips thousands separators from currency string

```ts
stripThousandSeparators('$1,000,000.56999') // => '$1000000.56999'
```


### "String" Methods

#### capitalize

> Capitalizes first character of string

```ts
capitalize('abc def') // => 'Abc def'
```

#### replaceAll

> Allows for multiple replacements for given value

```ts
replaceAll('{{attribute}}', [[/{{/, ':'], [/}}/, '']]) // => ':attribute'
```

#### titleize

> Capitalizes all the words apart from the likes of an

```ts
titleize('something to say') // => 'Something to Say'
```

#### trim

> Trim spaces around string or array of strings

```ts
trim('   ') // => ''
trim(' abc  ') // => 'abc'
trim(['', '   ', 'abc']) // => ['', '', 'abc']
```

### "Number" Methods

#### currencyToBigDecimal

> returns currency string to equivalent big decimal number

```ts
currencyToBigDecimal({ currencyAmount: '$1,000,000.56999' }) // => 1000000.56
```

### "Object" Methods

#### deepDiff

> returns deep differences between two objects 

```ts
const input = { one: 1, two: 2 };
deepDiff(input, input) // => {}

deepDiff({...input, two: 4}, input) // => { two: 2 }
deepDiff(input, {...input, two: 4}) // => { two: 4 }

deepDiff({...input, vehicle: { truck: 4}}, b) // => {}
deepDiff(a, {...input, vehicle: { truck: 4}}) // => { vehicle: { truck: 4 } }
```

#### deepDiffWithDetails.ts

> returns deep detailed differences between two objects 

```ts
const input = { one: 1, two: 2 };
deepDiffWithDetails(input, input) // => { added: {}, deleted: {}, updated: {} }

deepDiffWithDetails({...input, two: 4}, input) // => { added: {}, deleted: {}, updated: { two: 2 } }
deepDiffWithDetails(input, {...input, two: 4})  // => { added: {}, deleted: {}, updated: { two: 4 }  }

deepDiffWithDetails({...input, vehicle: { truck: 4}}, b) // => { added: {}, deleted: {}, updated: {} }
deepDiffWithDetails(a, {...input, vehicle: { truck: 4}}) // => { added: { vehicle: { truck: 4 } }, deleted: {}, updated: {} }
```

#### dot

> flattens given object into dot notation keys

```ts
const input = { a: { b: { c: 1 } } };
dot(input) // => { 'a.b.c': 1 }
dot(input, {separator: '_'}) // => { a_b_c: 1 }
```

#### dottedKeys

> returns list of flattened dotted keys for given object

```ts
const input = { addresses: [{ city: 1 }] };

dottedKeys(input) // => ['addresses.0.city']
dottedKeys(input, {separator: '_'}) // => ['addresses_0_city']

// with brackets around array indexes
dottedKeys(input, { useBrackets: true }) // => ['addresses[0].city']
dottedKeys(input, {separator: '_', useBrackets: true}) // => ['addresses[0]_city']
```

#### dottedOmit

> returns object without matching keys to omit

```ts
const input = {a: 1, b: 2, d: {f: 3, g: 2}};

dottedOmit(input, ['b', 'd.f']) // => {"a": 1,"d": {"g": 2}}
dottedOmit(input, ['d']) // => {"a": 1, "b": 2}}
```

#### dottedPick

> returns object consisting of matching dotted paths

```ts
const input = {a: 1, b: 2, d: {f: 3, g: 2}};

dottedPick(input, ['b', 'd.f']) // => { b: 2, d: { f: 3 } }
dottedPick(input, ['d']) // => { d: { f: 3 } }
```

#### matchesSearchPaths

> returns true if dotted key path matches one of given paths

```ts
matchesSearchPaths('a', ['a']) // => true 
matchesSearchPaths('a.ba', ['a']) // => true 

matchesSearchPaths('aa', ['a']) // => false 
```

#### undot

> hydrates dotted object

```ts
undot({ 'a.b.c': 1 }) // => { a: { b: { c: 1 } } }
undot({ a_b_c: 1 }, {separator: '_'}) // => { a: { b: { c: 1 } } }
```