@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.

Files changed (42) hide show
  1. package/.babelrc.json +3 -0
  2. package/.idea/modules.xml +8 -0
  3. package/.idea/s3-js-deep-purple-lib-utils.iml +12 -0
  4. package/README.md +13 -3
  5. package/bin/ascii-art.txt +36 -0
  6. package/bin/preinstall.sh +11 -0
  7. package/bin/pwned.txt +9 -0
  8. package/dist/declarations/src/array.d.ts +6 -0
  9. package/dist/declarations/src/casing.d.ts +8 -0
  10. package/dist/declarations/src/index.d.ts +10 -0
  11. package/dist/declarations/src/is-empty.d.ts +2 -0
  12. package/dist/declarations/src/number.d.ts +5 -0
  13. package/dist/declarations/src/object.d.ts +8 -0
  14. package/dist/declarations/src/string.d.ts +6 -0
  15. package/dist/declarations/src/to-hash.d.ts +2 -0
  16. package/dist/declarations/src/to-path.d.ts +3 -0
  17. package/dist/declarations/src/types.d.ts +15 -0
  18. package/dist/declarations/src/url.d.ts +4 -0
  19. package/dist/s3p-js-deep-purple-utils.cjs.d.ts +1 -0
  20. package/dist/s3p-js-deep-purple-utils.cjs.dev.js +310 -0
  21. package/dist/s3p-js-deep-purple-utils.cjs.js +7 -0
  22. package/dist/s3p-js-deep-purple-utils.cjs.prod.js +310 -0
  23. package/dist/s3p-js-deep-purple-utils.esm.js +260 -0
  24. package/jest.config.coverage.json +6 -0
  25. package/package.json +23 -3
  26. package/src/array.js +24 -0
  27. package/src/casing.ts +70 -0
  28. package/src/index.ts +10 -0
  29. package/src/is-empty.js +8 -0
  30. package/src/number.js +40 -0
  31. package/src/object.ts +45 -0
  32. package/src/string.js +73 -0
  33. package/src/to-hash.ts +3 -0
  34. package/src/to-path.ts +6 -0
  35. package/src/types.ts +24 -0
  36. package/src/url.js +22 -0
  37. package/tests/__snapshots__/casing.spec.js.snap +35 -0
  38. package/tests/casing.spec.js +29 -0
  39. package/tests/number.spec.js +67 -0
  40. package/tests/object.spec.ts +77 -0
  41. package/tests/string.spec.js +77 -0
  42. 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'
@@ -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
@@ -0,0 +1,3 @@
1
+ const toHash = (value = '/'): string => value.replace(/[/.]/g, '|')
2
+
3
+ export default toHash
package/src/to-path.ts ADDED
@@ -0,0 +1,6 @@
1
+ import {PathPartType} from './types'
2
+
3
+ const toPath = (path: PathPartType | PathPartType[]): string =>
4
+ Array.isArray(path) ? path.filter(Boolean).join('.') : path || ''
5
+
6
+ export default toPath
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
+ })
package/tsconfig.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "allowJs": true
5
+ },
6
+ "include": ["./src"]
7
+ }