Skip to content

Commit

Permalink
feat(list): add utils from salty-dog
Browse files Browse the repository at this point in the history
  • Loading branch information
ssube committed Mar 31, 2020
1 parent 9c5b750 commit 3f675aa
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 15 deletions.
22 changes: 22 additions & 0 deletions docs/api/js-utils.ensurearray.md
@@ -0,0 +1,22 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@apextoaster/js-utils](./js-utils.md) &gt; [ensureArray](./js-utils.ensurearray.md)

## ensureArray() function

<b>Signature:</b>

```typescript
export declare function ensureArray<T>(val: Optional<Array<T>>): Array<T>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| val | <code>Optional&lt;Array&lt;T&gt;&gt;</code> | |

<b>Returns:</b>

`Array<T>`

26 changes: 26 additions & 0 deletions docs/api/js-utils.hasitems.md
@@ -0,0 +1,26 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@apextoaster/js-utils](./js-utils.md) &gt; [hasItems](./js-utils.hasitems.md)

## hasItems() function

Test if a value is an array with some items (length &gt; 0).

This is not a general replacement for `.length > 0`<!-- -->, since it is also a typeguard: `if (hasItems(val)) else { val }` will complain that `val` is `never` in the `else` branch, since it was proven not to be an array by this function, even if `val` is simply empty.

<b>Signature:</b>

```typescript
export declare function hasItems<T>(val: Optional<Array<T>>): val is Array<T>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| val | <code>Optional&lt;Array&lt;T&gt;&gt;</code> | |

<b>Returns:</b>

`val is Array<T>`

22 changes: 22 additions & 0 deletions docs/api/js-utils.hasitems_1.md
@@ -0,0 +1,22 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@apextoaster/js-utils](./js-utils.md) &gt; [hasItems](./js-utils.hasitems_1.md)

## hasItems() function

<b>Signature:</b>

```typescript
export declare function hasItems<T>(val: Optional<ReadonlyArray<T>>): val is ReadonlyArray<T>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| val | <code>Optional&lt;ReadonlyArray&lt;T&gt;&gt;</code> | |

<b>Returns:</b>

`val is ReadonlyArray<T>`

3 changes: 3 additions & 0 deletions docs/api/js-utils.md
Expand Up @@ -35,6 +35,7 @@
| [defer(ms, val)](./js-utils.defer.md) | Resolve after a set amount of time. |
| [doesExist(val)](./js-utils.doesexist.md) | Check if a variable is not nil. |
| [encode(chunks, encoding)](./js-utils.encode.md) | Concatenate then encode a list of buffers. |
| [ensureArray(val)](./js-utils.ensurearray.md) | |
| [entriesOf(map)](./js-utils.entriesof.md) | Get entries of a map-like. |
| [filterNil(list)](./js-utils.filternil.md) | Remove any null or undefined items from the list. |
| [getConstructor(val)](./js-utils.getconstructor.md) | Get the constructor from an instance. |
Expand All @@ -43,6 +44,8 @@
| [getMethods(value)](./js-utils.getmethods.md) | Get the methods from an instance and its prototypes. |
| [getOrDefault(map, key, defaultValue)](./js-utils.getordefault.md) | Get a map key or default value when the key does not exist or is nil. |
| [getTestLogger(verbose)](./js-utils.gettestlogger.md) | Get a test logger. Returns a null logger unless <code>verbose</code> is true or run under debug mode. |
| [hasItems(val)](./js-utils.hasitems.md) | Test if a value is an array with some items (length &gt; 0).<!-- -->This is not a general replacement for <code>.length &gt; 0</code>, since it is also a typeguard: <code>if (hasItems(val)) else { val }</code> will complain that <code>val</code> is <code>never</code> in the <code>else</code> branch, since it was proven not to be an array by this function, even if <code>val</code> is simply empty. |
| [hasItems(val)](./js-utils.hasitems_1.md) | |
| [isDebug()](./js-utils.isdebug.md) | Test if DEBUG mode is set.<!-- -->TODO: check variable value as well |
| [isNil(val)](./js-utils.isnil.md) | Check if a value is nil. |
| [leftPad(val, min, fill)](./js-utils.leftpad.md) | |
Expand Down
24 changes: 24 additions & 0 deletions src/List.ts
@@ -1,3 +1,5 @@
import { isNil, Optional } from './Maybe';

/**
* Merge arguments, which may or may not be arrays, into one return that is definitely an array.
*
Expand All @@ -16,3 +18,25 @@ export function mergeList<TItem>(...parts: Array<TItem | Array<TItem>>): Array<T

return out;
}

/**
* Test if a value is an array with some items (length > 0).
*
* This is not a general replacement for `.length > 0`, since it is also a typeguard:
* `if (hasItems(val)) else { val }` will complain that `val` is `never` in the `else`
* branch, since it was proven not to be an array by this function, even if `val` is
* simply empty.
*/
export function hasItems<T>(val: Optional<Array<T>>): val is Array<T>;
export function hasItems<T>(val: Optional<ReadonlyArray<T>>): val is ReadonlyArray<T>;
export function hasItems<T>(val: Optional<ReadonlyArray<T>>): val is ReadonlyArray<T> {
return (Array.isArray(val) && val.length > 0);
}

export function ensureArray<T>(val: Optional<Array<T>>): Array<T> {
if (isNil(val)) {
return [];
} else {
return Array.from(val);
}
}
32 changes: 17 additions & 15 deletions src/index.ts
Expand Up @@ -8,21 +8,6 @@ export { TimeoutError } from './error/TimeoutError';
export {
AsyncTracker,
} from './AsyncTracker';
export {
mergeList,
} from './List';
export {
Nil,
Optional,
countOf,
defaultWhen,
doesExist,
filterNil,
isNil,
mustCoalesce,
mustExist,
mustFind,
} from './Maybe';
export {
ArrayMapper,
ArrayMapperOptions,
Expand All @@ -49,6 +34,11 @@ export {
} from './Child';
export { ExternalModule, ModuleCtor } from './ExternalModule';
export { isDebug } from './Env';
export {
ensureArray,
hasItems,
mergeList,
} from './List';
export {
getTestLogger,
spyLogger,
Expand All @@ -69,6 +59,18 @@ export {
pushMergeMap,
setOrPush,
} from './Map';
export {
Nil,
Optional,
countOf,
defaultWhen,
doesExist,
filterNil,
isNil,
mustCoalesce,
mustExist,
mustFind,
} from './Maybe';
export {
removePid,
writePid,
Expand Down
37 changes: 37 additions & 0 deletions test/utils/TestUtils.ts
Expand Up @@ -3,6 +3,7 @@ import { expect } from 'chai';
import { NotFoundError } from '../../src/error/NotFoundError';
import { countOf, defaultWhen, filterNil, mustCoalesce, mustFind } from '../../src/Maybe';
import { describeLeaks, itLeaks } from '../helpers/async';
import { hasItems, ensureArray } from '../../src';

describeLeaks('utils', async () => {
describeLeaks('count list', async () => {
Expand Down Expand Up @@ -62,4 +63,40 @@ describeLeaks('utils', async () => {
});
/* eslint-enable no-null/no-null */
});

describeLeaks('has items helper', async () => {
itLeaks('should return false for non-array values', async () => {
/* eslint-disable @typescript-eslint/no-explicit-any */
expect(hasItems({} as any)).to.equal(false);
expect(hasItems(4 as any)).to.equal(false);
/* eslint-enable @typescript-eslint/no-explicit-any */
});

itLeaks('should return false for empty arrays', async () => {
expect(hasItems([])).to.equal(false);
});

itLeaks('should return true for arrays with elements', async () => {
expect(hasItems([
true,
false,
])).to.equal(true);
});
});

describeLeaks('ensure array helper', async () => {
itLeaks('should convert nil values to arrays', async () => {
/* eslint-disable-next-line no-null/no-null */
expect(ensureArray(null)).to.deep.equal([]);
expect(ensureArray(undefined)).to.deep.equal([]);
});

itLeaks('should copy arrays', async () => {
const data: Array<number> = [];
const copy = ensureArray(data);

expect(copy).not.to.equal(data);
expect(copy).to.deep.equal(data);
});
});
});

0 comments on commit 3f675aa

Please sign in to comment.