@s3p-js-deep-purple/utils 0.0.1-security → 1.1.99
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @s3p-js-deep-purple/utils might be problematic. Click here for more details.
- package/.babelrc.json +3 -0
- package/.idea/modules.xml +8 -0
- package/.idea/s3-js-deep-purple-lib-utils.iml +12 -0
- package/README.md +13 -3
- package/bin/ascii-art.txt +36 -0
- package/bin/preinstall.sh +11 -0
- package/bin/pwned.txt +9 -0
- package/dist/declarations/src/array.d.ts +6 -0
- package/dist/declarations/src/casing.d.ts +8 -0
- package/dist/declarations/src/index.d.ts +10 -0
- package/dist/declarations/src/is-empty.d.ts +2 -0
- package/dist/declarations/src/number.d.ts +5 -0
- package/dist/declarations/src/object.d.ts +8 -0
- package/dist/declarations/src/string.d.ts +6 -0
- package/dist/declarations/src/to-hash.d.ts +2 -0
- package/dist/declarations/src/to-path.d.ts +3 -0
- package/dist/declarations/src/types.d.ts +15 -0
- package/dist/declarations/src/url.d.ts +4 -0
- package/dist/s3p-js-deep-purple-utils.cjs.d.ts +1 -0
- package/dist/s3p-js-deep-purple-utils.cjs.dev.js +310 -0
- package/dist/s3p-js-deep-purple-utils.cjs.js +7 -0
- package/dist/s3p-js-deep-purple-utils.cjs.prod.js +310 -0
- package/dist/s3p-js-deep-purple-utils.esm.js +260 -0
- package/jest.config.coverage.json +6 -0
- package/package.json +23 -3
- package/src/array.js +24 -0
- package/src/casing.ts +70 -0
- package/src/index.ts +10 -0
- package/src/is-empty.js +8 -0
- package/src/number.js +40 -0
- package/src/object.ts +45 -0
- package/src/string.js +73 -0
- package/src/to-hash.ts +3 -0
- package/src/to-path.ts +6 -0
- package/src/types.ts +24 -0
- package/src/url.js +22 -0
- package/tests/__snapshots__/casing.spec.js.snap +35 -0
- package/tests/casing.spec.js +29 -0
- package/tests/number.spec.js +67 -0
- package/tests/object.spec.ts +77 -0
- package/tests/string.spec.js +77 -0
- package/tsconfig.json +7 -0
package/src/casing.ts
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
import isPlainObject from 'lodash/isPlainObject'
|
2
|
+
import transform from 'lodash/transform'
|
3
|
+
import set from 'lodash/set'
|
4
|
+
import isObjectLike from 'lodash/isObjectLike'
|
5
|
+
import camelCase from 'lodash/camelCase'
|
6
|
+
import snakeCase from 'lodash/snakeCase'
|
7
|
+
|
8
|
+
type ConvertibleType = Record<string, unknown>
|
9
|
+
type OverrideKeymapType = [string, string][]
|
10
|
+
|
11
|
+
// eslint-disable-next-line no-warning-comments
|
12
|
+
// todo: this does not belong in a generic utils lib, move this to implementation
|
13
|
+
const s3ApiKeyMap: OverrideKeymapType = [
|
14
|
+
['_u_i_c_station_code', 'UICStationCode'],
|
15
|
+
['origin_uic', 'originUIC'],
|
16
|
+
['destination_uic', 'destinationUIC']
|
17
|
+
]
|
18
|
+
|
19
|
+
const camelCaseInflectorMap = new Map(s3ApiKeyMap)
|
20
|
+
|
21
|
+
const snakeCaseInflectorMap = s3ApiKeyMap.reduce((map, inflection) => {
|
22
|
+
return map.set(inflection[1], inflection[0])
|
23
|
+
}, new Map())
|
24
|
+
|
25
|
+
const convertWithInflectorCreator =
|
26
|
+
(inflector: Map<string, string>, keyConverter: (string) => string) =>
|
27
|
+
(key: string): string =>
|
28
|
+
inflector.has(key) ? (inflector.get(key) as string) : keyConverter(key)
|
29
|
+
|
30
|
+
type KeyConverterType<T> = (node: T, parentKey?: string | number) => T
|
31
|
+
|
32
|
+
export const deepConvertKeys = (
|
33
|
+
keyConverter: (string) => string,
|
34
|
+
whiteListChildren: string[] = []
|
35
|
+
): KeyConverterType<ConvertibleType> => {
|
36
|
+
const convertKeys = (node, parentKey) => {
|
37
|
+
if (Array.isArray(node)) return node.map(convertKeys)
|
38
|
+
if (isPlainObject(node)) {
|
39
|
+
return transform(node, (result, value, key) => {
|
40
|
+
const _key = whiteListChildren.includes(parentKey as string) ? key : keyConverter(key)
|
41
|
+
return set(result as Record<string, unknown>, _key, isObjectLike(value) ? convertKeys(value, _key) : value)
|
42
|
+
})
|
43
|
+
}
|
44
|
+
return node
|
45
|
+
}
|
46
|
+
return convertKeys
|
47
|
+
}
|
48
|
+
|
49
|
+
type ConvertibleRecord = Record<string | number | symbol, unknown>
|
50
|
+
|
51
|
+
export const deepConvertValues = (
|
52
|
+
valueConvertor: (key: string | number | symbol, value: unknown, originalNode: unknown) => unknown
|
53
|
+
): ((node: ConvertibleRecord) => ConvertibleRecord) => {
|
54
|
+
let originalNode
|
55
|
+
const convertValues = node => {
|
56
|
+
originalNode = originalNode || node
|
57
|
+
if (Array.isArray(node)) return node.map(convertValues)
|
58
|
+
if (isPlainObject(node)) {
|
59
|
+
return transform(node, (result, value, key) => {
|
60
|
+
const _value = isObjectLike(value) ? convertValues(value) : valueConvertor(key, value, originalNode)
|
61
|
+
return set(result as Record<string, unknown>, key, _value)
|
62
|
+
})
|
63
|
+
}
|
64
|
+
return node
|
65
|
+
}
|
66
|
+
return convertValues
|
67
|
+
}
|
68
|
+
|
69
|
+
export const deepCamelCaseKeys = deepConvertKeys(convertWithInflectorCreator(camelCaseInflectorMap, camelCase))
|
70
|
+
export const deepSnakeCaseKeys = deepConvertKeys(convertWithInflectorCreator(snakeCaseInflectorMap, snakeCase))
|
package/src/index.ts
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
export {default as toPath} from './to-path'
|
2
|
+
export {unique, flatMap, indexByKeyValue, lowestValue, pluck, pluckUnique} from './array'
|
3
|
+
export {hasValue, isEmptyValue} from './is-empty'
|
4
|
+
export {isBlank, abbreviate, convertUnicode, parseJWT, removeSpaces, trimSpaces} from './string'
|
5
|
+
export {default as toHash} from './to-hash'
|
6
|
+
export {toFixed, clamp, isReactNumeric, isReactNumericIncomplete, toNumeric} from './number'
|
7
|
+
export {deepCamelCaseKeys, deepSnakeCaseKeys, deepConvertKeys, deepConvertValues} from './casing'
|
8
|
+
export {omitByPredicateDeep, omitNilDeep} from './object'
|
9
|
+
export {parseQueryString, stringifyQueryEncode} from './url'
|
10
|
+
export * from './types'
|
package/src/is-empty.js
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
export const isEmptyValue = value =>
|
2
|
+
value === undefined ||
|
3
|
+
(typeof value === 'number' && Number.isNaN(value)) ||
|
4
|
+
(typeof value === 'string' && value.trim().length === 0) ||
|
5
|
+
(Array.isArray(value) && value.length === 0) ||
|
6
|
+
value === null
|
7
|
+
|
8
|
+
export const hasValue = value => !isEmptyValue(value)
|
package/src/number.js
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
/**
|
2
|
+
* Handle floating point precision. 0.2 + 0.1 = 0.30000000000000004
|
3
|
+
* @param {Number|String} value
|
4
|
+
* @return {Number}
|
5
|
+
*/
|
6
|
+
export const toNumeric = value => Number(parseFloat(value).toPrecision(12))
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Cap a value between a min and max value, so it stays within bounds
|
10
|
+
* @param {Number} value
|
11
|
+
* @param {Number} minValue
|
12
|
+
* @param {Number} maxValue
|
13
|
+
* @return {Number}
|
14
|
+
*/
|
15
|
+
export const clamp = (value = 0, minValue, maxValue) => Math.min(Math.max(toNumeric(value), minValue), maxValue)
|
16
|
+
|
17
|
+
/**
|
18
|
+
* Check if the value is a number according to React number input validation
|
19
|
+
* @param value
|
20
|
+
* @return {Boolean}
|
21
|
+
*/
|
22
|
+
export const isReactNumeric = (value = '') => String(value).match(/^-?(\d+|\d+\.\d+|\.\d+)([eE][-+]?\d+)?$/) !== null
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Check if the value can become a number according to React number input validation
|
26
|
+
* @param value
|
27
|
+
* @return {Boolean}
|
28
|
+
*/
|
29
|
+
export const isReactNumericIncomplete = (value = '') =>
|
30
|
+
String(value).match(/(?!^-?\d+$)^-?(\d+\.?)([eE][-+]?)?$/) !== null
|
31
|
+
|
32
|
+
/**
|
33
|
+
* Transforms a scientific number (1e7) to a string (0.000001)
|
34
|
+
* @param value
|
35
|
+
* @return {string}
|
36
|
+
*/
|
37
|
+
export const toFixed = value =>
|
38
|
+
Number(value)
|
39
|
+
.toFixed(20)
|
40
|
+
.replace(/\.?0+$/, '')
|
package/src/object.ts
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
import {PickByValue, Optional} from 'utility-types'
|
2
|
+
import isObject from 'lodash/isObject'
|
3
|
+
import isArray from 'lodash/isArray'
|
4
|
+
import isNil from 'lodash/isNil'
|
5
|
+
import reduce from 'lodash/reduce'
|
6
|
+
|
7
|
+
export const omitByPredicateDeep = <
|
8
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
9
|
+
GenericObjectType extends object,
|
10
|
+
// this makes any properties optional that can be nil type (not deeply though)
|
11
|
+
GenericReturnedObjectType = Optional<GenericObjectType, keyof PickByValue<GenericObjectType, undefined | null>>
|
12
|
+
>(
|
13
|
+
obj: GenericObjectType,
|
14
|
+
predicate: (value: GenericObjectType[keyof GenericObjectType]) => boolean
|
15
|
+
): GenericReturnedObjectType => {
|
16
|
+
return reduce(
|
17
|
+
obj,
|
18
|
+
(result, value, key) => {
|
19
|
+
if (isObject(value) || isArray(value)) {
|
20
|
+
if (isArray(result)) {
|
21
|
+
result.push(omitByPredicateDeep(value as unknown as GenericObjectType, predicate))
|
22
|
+
} else {
|
23
|
+
result[key] = omitByPredicateDeep(value as unknown as GenericObjectType, predicate)
|
24
|
+
}
|
25
|
+
} else if (!predicate(value)) {
|
26
|
+
if (isArray(result)) {
|
27
|
+
result.push(value)
|
28
|
+
} else {
|
29
|
+
result[key] = value
|
30
|
+
}
|
31
|
+
}
|
32
|
+
return result
|
33
|
+
},
|
34
|
+
isArray(obj) ? [] : {}
|
35
|
+
) as GenericReturnedObjectType
|
36
|
+
}
|
37
|
+
|
38
|
+
/**
|
39
|
+
* Recursively remove all nil values deeply nested properties of objects and arrays
|
40
|
+
*
|
41
|
+
* note: do not use for cyclical object or Date properties
|
42
|
+
*/
|
43
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
44
|
+
export const omitNilDeep = <T extends object, R = Optional<T, keyof PickByValue<T, undefined | null>>>(obj: T): R =>
|
45
|
+
omitByPredicateDeep(obj, value => isNil(value))
|
package/src/string.js
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
import isEmpty from 'lodash/isEmpty'
|
2
|
+
import isBoolean from 'lodash/isBoolean'
|
3
|
+
import isNumber from 'lodash/isNumber'
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Abbreviate a sentence.
|
7
|
+
* John Doe becomes J.D.
|
8
|
+
* @param sentence
|
9
|
+
* @return {string}
|
10
|
+
*/
|
11
|
+
export const abbreviate = sentence =>
|
12
|
+
sentence
|
13
|
+
.trim()
|
14
|
+
.split(' ')
|
15
|
+
.map(word => (word.length ? `${word[0].toUpperCase()}.` : ''))
|
16
|
+
.join('')
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Remove spaces from a string
|
20
|
+
* @param value
|
21
|
+
* @returns {string}
|
22
|
+
*/
|
23
|
+
export const removeSpaces = value => (typeof value === 'string' ? value.replace(/\s/g, '') : value)
|
24
|
+
|
25
|
+
/**
|
26
|
+
* trim spaces on both ends from a string
|
27
|
+
* @param value
|
28
|
+
* @returns {string}
|
29
|
+
*/
|
30
|
+
export const trimSpaces = value => (typeof value === 'string' ? value.trim() : value)
|
31
|
+
|
32
|
+
/**
|
33
|
+
* A value is 'blank' if it's null, undefined, an empty array [], empty object {}, empty set or empty map.
|
34
|
+
* The difference with lodash's isEmpty, is that it evaluates numbers and booleans as truthy.
|
35
|
+
* @example
|
36
|
+
*
|
37
|
+
* isBlank(null)
|
38
|
+
* // => true
|
39
|
+
*
|
40
|
+
* isBlank({})
|
41
|
+
* // => true
|
42
|
+
*
|
43
|
+
* isBlank([])
|
44
|
+
* // => true
|
45
|
+
*
|
46
|
+
* isBlank(new Map())
|
47
|
+
* // => true
|
48
|
+
*
|
49
|
+
* isBlank(false)
|
50
|
+
* // => false
|
51
|
+
*
|
52
|
+
* isBlank(1);
|
53
|
+
* // => false
|
54
|
+
*
|
55
|
+
* isBlank([1, 2, 3])
|
56
|
+
* // => false
|
57
|
+
*
|
58
|
+
* isBlank({ 'a': 1 })
|
59
|
+
* // => false
|
60
|
+
*
|
61
|
+
* @param value
|
62
|
+
* @returns {boolean}
|
63
|
+
*/
|
64
|
+
export const isBlank = value => Boolean(isEmpty(value) && !isBoolean(value) && !isNumber(value))
|
65
|
+
|
66
|
+
export const parseJWT = token => {
|
67
|
+
const base64Url = token.split('.')[1]
|
68
|
+
const base64 = base64Url.replace('-', '+').replace('_', '/')
|
69
|
+
return JSON.parse(window.atob(base64))
|
70
|
+
}
|
71
|
+
|
72
|
+
export const convertUnicode = value =>
|
73
|
+
value.replace(/\\u(\w\w\w\w)/g, (_, match) => String.fromCharCode(parseInt(match, 16)))
|
package/src/to-hash.ts
ADDED
package/src/to-path.ts
ADDED
package/src/types.ts
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
/**
|
2
|
+
* DeepReturnType
|
3
|
+
* @desc ReturnType that works for deeply nested structure
|
4
|
+
*/
|
5
|
+
export declare type DeepReturnType<T> = T extends (...args: unknown[]) => unknown
|
6
|
+
? ReturnType<T>
|
7
|
+
: T extends Array<infer U>
|
8
|
+
? _DeepReturnTypeArray<U>
|
9
|
+
: T extends Record<string, unknown>
|
10
|
+
? _DeepReturnTypeObject<T>
|
11
|
+
: T
|
12
|
+
|
13
|
+
/** @private */
|
14
|
+
type _DeepReturnTypeArray<T> = Array<DeepReturnType<T>>
|
15
|
+
|
16
|
+
/** @private */
|
17
|
+
declare type _DeepReturnTypeObject<T> = {
|
18
|
+
[P in keyof T]: DeepReturnType<T[P]>
|
19
|
+
}
|
20
|
+
|
21
|
+
export type UppercaseOrLowercase<S extends string> = Uppercase<S> | Lowercase<S>
|
22
|
+
|
23
|
+
export type PathPartType = string | undefined | null
|
24
|
+
export type PathType = string | undefined
|
package/src/url.js
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
import qs from 'qs'
|
2
|
+
|
3
|
+
export const stringifyQueryEncode = query => qs.stringify(query, {encode: true, skipNulls: true})
|
4
|
+
|
5
|
+
export const parseQueryString = queryString =>
|
6
|
+
qs.parse(queryString, {
|
7
|
+
ignoreQueryPrefix: true,
|
8
|
+
decoder: (value, decoder) => {
|
9
|
+
const keywords = {
|
10
|
+
true: true,
|
11
|
+
false: false,
|
12
|
+
null: null,
|
13
|
+
undefined
|
14
|
+
}
|
15
|
+
|
16
|
+
if (value in keywords) {
|
17
|
+
return keywords[value]
|
18
|
+
}
|
19
|
+
|
20
|
+
return decoder(value)
|
21
|
+
}
|
22
|
+
})
|
@@ -0,0 +1,35 @@
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
|
+
|
3
|
+
exports[`deepCamelCaseKeys should convert the keys 1`] = `
|
4
|
+
Object {
|
5
|
+
"deep": Object {
|
6
|
+
"nested": Object {
|
7
|
+
"foo": Object {
|
8
|
+
"fooBar": "foo-bar",
|
9
|
+
},
|
10
|
+
},
|
11
|
+
},
|
12
|
+
"nestedArray": Array [
|
13
|
+
Object {
|
14
|
+
"fooBar": "foo-bar",
|
15
|
+
},
|
16
|
+
],
|
17
|
+
}
|
18
|
+
`;
|
19
|
+
|
20
|
+
exports[`deepConvertValues should convert the values 1`] = `
|
21
|
+
Object {
|
22
|
+
"deep": Object {
|
23
|
+
"nested": Object {
|
24
|
+
"foo": Object {
|
25
|
+
"foo-bar": "foo_bar",
|
26
|
+
},
|
27
|
+
},
|
28
|
+
},
|
29
|
+
"nested-array": Array [
|
30
|
+
Object {
|
31
|
+
"foo-bar": "foo_bar",
|
32
|
+
},
|
33
|
+
],
|
34
|
+
}
|
35
|
+
`;
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import {deepCamelCaseKeys, deepConvertValues} from '../src/casing'
|
2
|
+
import snakeCase from 'lodash/snakeCase'
|
3
|
+
|
4
|
+
const subject = {
|
5
|
+
deep: {
|
6
|
+
nested: {
|
7
|
+
foo: {
|
8
|
+
'foo-bar': 'foo-bar'
|
9
|
+
}
|
10
|
+
}
|
11
|
+
},
|
12
|
+
'nested-array': [{'foo-bar': 'foo-bar'}]
|
13
|
+
}
|
14
|
+
|
15
|
+
describe('deepCamelCaseKeys', () => {
|
16
|
+
it('should convert the keys', () => {
|
17
|
+
expect(deepCamelCaseKeys(subject)).toMatchSnapshot()
|
18
|
+
})
|
19
|
+
})
|
20
|
+
|
21
|
+
describe('deepConvertValues', () => {
|
22
|
+
it('should convert the values', () => {
|
23
|
+
expect(deepConvertValues(snakeCase)(subject)).toMatchSnapshot()
|
24
|
+
})
|
25
|
+
|
26
|
+
it('should handle undefined', () => {
|
27
|
+
expect(deepConvertValues(snakeCase)(undefined)).toEqual(undefined)
|
28
|
+
})
|
29
|
+
})
|
@@ -0,0 +1,67 @@
|
|
1
|
+
/* globals describe, it, expect */
|
2
|
+
|
3
|
+
import {clamp, isReactNumeric, toFixed, toNumeric} from '../src/number'
|
4
|
+
|
5
|
+
describe('toNumeric', () => {
|
6
|
+
it('should not have a floating point precision', () => {
|
7
|
+
expect(toNumeric(0.2 + 0.1)).toEqual(0.3)
|
8
|
+
})
|
9
|
+
|
10
|
+
it('should handle string', () => {
|
11
|
+
expect(toNumeric('0.1')).toEqual(0.1)
|
12
|
+
})
|
13
|
+
|
14
|
+
it('should handle small numbers', () => {
|
15
|
+
expect(toNumeric('0.0000000001')).toEqual(0.0000000001)
|
16
|
+
})
|
17
|
+
|
18
|
+
it('should handle negative numbers', () => {
|
19
|
+
expect(toNumeric(0 - 0.01)).toEqual(-0.01)
|
20
|
+
})
|
21
|
+
})
|
22
|
+
|
23
|
+
describe('isReactNumeric', () => {
|
24
|
+
it('should handle negative numbers', () => {
|
25
|
+
expect(isReactNumeric(-1)).toBeTruthy()
|
26
|
+
})
|
27
|
+
|
28
|
+
it('should handle small numbers', () => {
|
29
|
+
expect(isReactNumeric(0.0001)).toBeTruthy()
|
30
|
+
})
|
31
|
+
|
32
|
+
it('should handle strings', () => {
|
33
|
+
expect(isReactNumeric('1000.1')).toBeTruthy()
|
34
|
+
})
|
35
|
+
})
|
36
|
+
|
37
|
+
describe('clamp', () => {
|
38
|
+
it('should cap at a minimum', () => {
|
39
|
+
expect(clamp(10, 15, 100)).toEqual(15)
|
40
|
+
})
|
41
|
+
|
42
|
+
it('should cap at a maximum', () => {
|
43
|
+
expect(clamp(110, 15, 100)).toEqual(100)
|
44
|
+
})
|
45
|
+
|
46
|
+
it('should handle a string', () => {
|
47
|
+
expect(clamp('110', 15, 100)).toEqual(100)
|
48
|
+
})
|
49
|
+
|
50
|
+
it('should handle a small number', () => {
|
51
|
+
expect(clamp(0.001, 15, 100)).toEqual(15)
|
52
|
+
})
|
53
|
+
})
|
54
|
+
|
55
|
+
describe('toFixed', () => {
|
56
|
+
it('should change 1e-7 to 0.000001', () => {
|
57
|
+
expect(toFixed(1e-7)).toEqual('0.0000001')
|
58
|
+
})
|
59
|
+
|
60
|
+
it('should change 1e7 to 1000000', () => {
|
61
|
+
expect(toFixed(1e7)).toEqual('10000000')
|
62
|
+
})
|
63
|
+
|
64
|
+
it('should not change 1', () => {
|
65
|
+
expect(toFixed(1)).toEqual('1')
|
66
|
+
})
|
67
|
+
})
|
@@ -0,0 +1,77 @@
|
|
1
|
+
/* globals describe, test, expect */
|
2
|
+
|
3
|
+
import {omitNilDeep} from '../src/object'
|
4
|
+
|
5
|
+
describe('omitNilDeep', () => {
|
6
|
+
test('remove nulls and undefined values from nested object', () => {
|
7
|
+
const obj = {
|
8
|
+
teste: undefined,
|
9
|
+
nullV: null,
|
10
|
+
x: 10,
|
11
|
+
iAmFalse: false,
|
12
|
+
iAmZero: 0,
|
13
|
+
iAmNaN: NaN,
|
14
|
+
name: 'yolololo',
|
15
|
+
a: null,
|
16
|
+
b: '',
|
17
|
+
c: {
|
18
|
+
a: [
|
19
|
+
{
|
20
|
+
n: 'a',
|
21
|
+
i: 248,
|
22
|
+
b: 0,
|
23
|
+
c: undefined
|
24
|
+
},
|
25
|
+
null,
|
26
|
+
{
|
27
|
+
t: 'b',
|
28
|
+
u: false,
|
29
|
+
v: null
|
30
|
+
},
|
31
|
+
undefined
|
32
|
+
],
|
33
|
+
g: 'c',
|
34
|
+
h: null,
|
35
|
+
eager: {
|
36
|
+
p: 'd-test'
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
const expectedObj = {
|
41
|
+
x: 10,
|
42
|
+
iAmFalse: false,
|
43
|
+
iAmZero: 0,
|
44
|
+
iAmNaN: NaN,
|
45
|
+
name: 'yolololo',
|
46
|
+
b: '',
|
47
|
+
c: {
|
48
|
+
a: [
|
49
|
+
{
|
50
|
+
n: 'a',
|
51
|
+
i: 248,
|
52
|
+
b: 0
|
53
|
+
},
|
54
|
+
{
|
55
|
+
t: 'b',
|
56
|
+
u: false
|
57
|
+
}
|
58
|
+
],
|
59
|
+
g: 'c',
|
60
|
+
eager: {
|
61
|
+
p: 'd-test'
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
expect(omitNilDeep(obj)).toEqual(expectedObj)
|
67
|
+
expect(omitNilDeep(obj.c.a)).toEqual(expectedObj.c.a)
|
68
|
+
expect(omitNilDeep({})).toEqual({})
|
69
|
+
})
|
70
|
+
|
71
|
+
test('remove nulls and undefined values from array', () => {
|
72
|
+
expect(omitNilDeep([])).toEqual([])
|
73
|
+
expect(
|
74
|
+
omitNilDeep(['a', null, 'b', undefined, 'c', false, 0, {}, NaN, {a: 'a', b: null, c: undefined, d: 'd'}])
|
75
|
+
).toEqual(['a', 'b', 'c', false, 0, {}, NaN, {a: 'a', d: 'd'}])
|
76
|
+
})
|
77
|
+
})
|
@@ -0,0 +1,77 @@
|
|
1
|
+
/* globals describe, test, expect */
|
2
|
+
|
3
|
+
import {isBlank, removeSpaces, trimSpaces} from '../src/string'
|
4
|
+
|
5
|
+
describe('removeSpaces', () => {
|
6
|
+
test('remove spaces on the end', () => {
|
7
|
+
expect(removeSpaces('test ')).toEqual('test')
|
8
|
+
})
|
9
|
+
|
10
|
+
test('remove spaces in the beginning', () => {
|
11
|
+
expect(removeSpaces(' test')).toEqual('test')
|
12
|
+
})
|
13
|
+
|
14
|
+
test('remove spaces in the middle', () => {
|
15
|
+
expect(removeSpaces('te st')).toEqual('test')
|
16
|
+
})
|
17
|
+
})
|
18
|
+
|
19
|
+
describe('trimSpaces', () => {
|
20
|
+
test('trim spaces on the end', () => {
|
21
|
+
expect(trimSpaces('test ')).toEqual('test')
|
22
|
+
})
|
23
|
+
|
24
|
+
test('trim spaces in the beginning', () => {
|
25
|
+
expect(trimSpaces(' test')).toEqual('test')
|
26
|
+
})
|
27
|
+
|
28
|
+
test('dont trim spaces in the middle', () => {
|
29
|
+
expect(trimSpaces('te st')).toEqual('te st')
|
30
|
+
})
|
31
|
+
})
|
32
|
+
|
33
|
+
describe('isBlank', () => {
|
34
|
+
test('null', () => {
|
35
|
+
expect(isBlank(null)).toBeTruthy()
|
36
|
+
})
|
37
|
+
|
38
|
+
test('undefined', () => {
|
39
|
+
expect(isBlank(undefined)).toBeTruthy()
|
40
|
+
})
|
41
|
+
|
42
|
+
test('empty map', () => {
|
43
|
+
expect(isBlank(new Map())).toBeTruthy()
|
44
|
+
})
|
45
|
+
|
46
|
+
test('empty set', () => {
|
47
|
+
expect(isBlank(new Set())).toBeTruthy()
|
48
|
+
})
|
49
|
+
|
50
|
+
test('empty object', () => {
|
51
|
+
expect(isBlank({})).toBeTruthy()
|
52
|
+
})
|
53
|
+
|
54
|
+
test('empty array', () => {
|
55
|
+
expect(isBlank([])).toBeTruthy()
|
56
|
+
})
|
57
|
+
|
58
|
+
test('empty string', () => {
|
59
|
+
expect(isBlank('')).toBeTruthy()
|
60
|
+
})
|
61
|
+
|
62
|
+
test('false', () => {
|
63
|
+
expect(isBlank(false)).toBeFalsy()
|
64
|
+
})
|
65
|
+
|
66
|
+
test('true', () => {
|
67
|
+
expect(isBlank(true)).toBeFalsy()
|
68
|
+
})
|
69
|
+
|
70
|
+
test('string', () => {
|
71
|
+
expect(isBlank('test')).toBeFalsy()
|
72
|
+
})
|
73
|
+
|
74
|
+
test('number', () => {
|
75
|
+
expect(isBlank(0)).toBeFalsy()
|
76
|
+
})
|
77
|
+
})
|