@coast/core-utils 0.0.2 → 0.0.6
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.
- package/dist/ArrayUtils.d.ts +9 -0
- package/dist/ArrayUtils.js +43 -0
- package/dist/ArrayUtils.js.map +1 -0
- package/dist/AssertionUtils.d.ts +11 -0
- package/dist/AssertionUtils.js +51 -0
- package/dist/AssertionUtils.js.map +1 -0
- package/dist/test/ArrayUtilsTest.d.ts +1 -0
- package/dist/test/ArrayUtilsTest.js +105 -0
- package/dist/test/ArrayUtilsTest.js.map +1 -0
- package/dist/test/AssertionUtilsTest.d.ts +1 -0
- package/dist/test/AssertionUtilsTest.js +130 -0
- package/dist/test/AssertionUtilsTest.js.map +1 -0
- package/jest.config.js +1 -0
- package/package.json +11 -1
- package/src/ArrayUtils.ts +62 -0
- package/src/AssertionUtils.ts +54 -0
- package/src/test/ArrayUtilsTest.ts +135 -0
- package/src/test/AssertionUtilsTest.ts +141 -0
- package/tsconfig.json +10 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { CoastException } from '@coast/core-types/exception/CoastException';
|
|
2
|
+
|
|
3
|
+
import { ArrayUtils } from '../ArrayUtils';
|
|
4
|
+
|
|
5
|
+
describe('ArrayUtils', () => {
|
|
6
|
+
describe('liftNonEmpty', () => {
|
|
7
|
+
it('returns the same array as a NonEmptyArray when given a non-empty array', () => {
|
|
8
|
+
const input = [1, 2, 3];
|
|
9
|
+
|
|
10
|
+
const result = ArrayUtils.liftNonEmpty(input);
|
|
11
|
+
|
|
12
|
+
expect(result).toEqual([1, 2, 3]);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('returns a single-element array', () => {
|
|
16
|
+
const input = ['only'];
|
|
17
|
+
|
|
18
|
+
const result = ArrayUtils.liftNonEmpty(input);
|
|
19
|
+
|
|
20
|
+
expect(result).toEqual(['only']);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('throws a CoastException when given an empty array', () => {
|
|
24
|
+
expect(() => ArrayUtils.liftNonEmpty([])).toThrow(CoastException);
|
|
25
|
+
expect(() => ArrayUtils.liftNonEmpty([])).toThrow('Cannot lift empty array');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('first', () => {
|
|
30
|
+
it('returns the first element of a non-empty array', () => {
|
|
31
|
+
expect(ArrayUtils.first([10, 20, 30])).toEqual(10);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('returns the first element of a single-element array', () => {
|
|
35
|
+
expect(ArrayUtils.first(['hello'])).toEqual('hello');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('returns undefined for an empty array', () => {
|
|
39
|
+
expect(ArrayUtils.first([])).toBeUndefined();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('returns undefined when given undefined', () => {
|
|
43
|
+
expect(ArrayUtils.first(undefined)).toBeUndefined();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('returns undefined when given null', () => {
|
|
47
|
+
expect(ArrayUtils.first(null)).toBeUndefined();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('isNonEmptyArray', () => {
|
|
52
|
+
it('returns true for a non-empty array', () => {
|
|
53
|
+
expect(ArrayUtils.isNonEmptyArray([1, 2, 3])).toEqual(true);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('returns true for a single-element array', () => {
|
|
57
|
+
expect(ArrayUtils.isNonEmptyArray(['item'])).toEqual(true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('returns false for an empty array', () => {
|
|
61
|
+
expect(ArrayUtils.isNonEmptyArray([])).toEqual(false);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('returns false for null', () => {
|
|
65
|
+
expect(ArrayUtils.isNonEmptyArray(null)).toEqual(false);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('returns false for undefined', () => {
|
|
69
|
+
expect(ArrayUtils.isNonEmptyArray(undefined)).toEqual(false);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('isUniformArray', () => {
|
|
74
|
+
it('returns true for an empty array', () => {
|
|
75
|
+
expect(ArrayUtils.isUniformArray([])).toEqual(true);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('returns false for a non-array value', () => {
|
|
79
|
+
expect(ArrayUtils.isUniformArray('not an array')).toEqual(false);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('returns false for null', () => {
|
|
83
|
+
expect(ArrayUtils.isUniformArray(null)).toEqual(false);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('returns false for undefined', () => {
|
|
87
|
+
expect(ArrayUtils.isUniformArray(undefined)).toEqual(false);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('returns true for an array of uniform string types', () => {
|
|
91
|
+
expect(ArrayUtils.isUniformArray(['a', 'b', 'c'])).toEqual(true);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('returns true for an array of uniform number types', () => {
|
|
95
|
+
expect(ArrayUtils.isUniformArray([1, 2, 3])).toEqual(true);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('returns false for an array of mixed types', () => {
|
|
99
|
+
expect(ArrayUtils.isUniformArray([1, 'two', 3])).toEqual(false);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('returns false for an array mixing numbers and booleans', () => {
|
|
103
|
+
expect(ArrayUtils.isUniformArray([1, true, 3])).toEqual(false);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe('with itemGuard', () => {
|
|
107
|
+
const isString = (item: unknown): item is string => typeof item === 'string';
|
|
108
|
+
const isNumber = (item: unknown): item is number => typeof item === 'number';
|
|
109
|
+
|
|
110
|
+
it('returns true when all items satisfy the guard', () => {
|
|
111
|
+
expect(ArrayUtils.isUniformArray(['a', 'b', 'c'], isString)).toEqual(true);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('returns false when any item fails the guard', () => {
|
|
115
|
+
expect(ArrayUtils.isUniformArray(['a', 1, 'c'], isString)).toEqual(false);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('returns true for an empty array regardless of guard', () => {
|
|
119
|
+
expect(ArrayUtils.isUniformArray([], isNumber)).toEqual(true);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('returns true when all items satisfy a number guard', () => {
|
|
123
|
+
expect(ArrayUtils.isUniformArray([1, 2, 3], isNumber)).toEqual(true);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('narrowing: correctly types result as string[] when guard passes', () => {
|
|
127
|
+
const value: unknown = ['x', 'y'];
|
|
128
|
+
|
|
129
|
+
if (ArrayUtils.isUniformArray(value, isString)) {
|
|
130
|
+
expect(value[0]).toEqual('x');
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { EntityType } from '@coast/core-types/common/EntityType';
|
|
2
|
+
import { EntityTypeLabels } from '@coast/core-types/common/EntityTypeLabels';
|
|
3
|
+
import { AssertionFailedException } from '@coast/core-types/exception/AssertionFailedException';
|
|
4
|
+
import { CoastException } from '@coast/core-types/exception/CoastException';
|
|
5
|
+
import { InvalidEntityReferenceException } from '@coast/core-types/exception/InvalidEntityReferenceException';
|
|
6
|
+
import { NotDefinedException } from '@coast/core-types/exception/NotDefinedException';
|
|
7
|
+
import { assertType } from '@coast/service-common/types/assertType';
|
|
8
|
+
import { Equals } from '@coast/service-common/types/Equals';
|
|
9
|
+
import { safeExpect } from '@paradoxical-io/common-test';
|
|
10
|
+
|
|
11
|
+
import { AssertionUtils } from '../AssertionUtils';
|
|
12
|
+
|
|
13
|
+
describe('AssertionUtils', () => {
|
|
14
|
+
describe('assertIsDefined', () => {
|
|
15
|
+
it('should throw if value is not defined', () => {
|
|
16
|
+
const x = undefined as object | undefined;
|
|
17
|
+
try {
|
|
18
|
+
AssertionUtils.assertIsDefined(x);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
expect(error).toBeInstanceOf(NotDefinedException);
|
|
21
|
+
safeExpect((error as NotDefinedException).message).toEqual('Value is not defined');
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should use custom error message', () => {
|
|
26
|
+
const x = undefined as object | undefined;
|
|
27
|
+
try {
|
|
28
|
+
AssertionUtils.assertIsDefined(x, 'x should exist...');
|
|
29
|
+
} catch (error) {
|
|
30
|
+
expect(error).toBeInstanceOf(NotDefinedException);
|
|
31
|
+
safeExpect((error as NotDefinedException).message).toEqual('x should exist...');
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should use custom Exception', () => {
|
|
36
|
+
const x = undefined as object | undefined;
|
|
37
|
+
try {
|
|
38
|
+
AssertionUtils.assertIsDefined(x, new CoastException('custom exception'));
|
|
39
|
+
} catch (error) {
|
|
40
|
+
expect(error).toBeInstanceOf(CoastException);
|
|
41
|
+
safeExpect((error as NotDefinedException).message).toEqual('custom exception');
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should not throw and should type narrow if value is defined', () => {
|
|
46
|
+
const x = '' as string | undefined;
|
|
47
|
+
assertType<Equals<typeof x, string | undefined>>();
|
|
48
|
+
|
|
49
|
+
AssertionUtils.assertIsDefined(x);
|
|
50
|
+
assertType<Equals<typeof x, string>>();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('assert', () => {
|
|
55
|
+
it('should throw AssertionFailedException if value is falsy', () => {
|
|
56
|
+
try {
|
|
57
|
+
AssertionUtils.assert(false);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
expect(error).toBeInstanceOf(AssertionFailedException);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should use custom error message', () => {
|
|
64
|
+
try {
|
|
65
|
+
AssertionUtils.assert(false, 'value must be truthy');
|
|
66
|
+
} catch (error) {
|
|
67
|
+
expect(error).toBeInstanceOf(AssertionFailedException);
|
|
68
|
+
safeExpect((error as AssertionFailedException).message).toEqual('value must be truthy');
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should use custom CoastException', () => {
|
|
73
|
+
try {
|
|
74
|
+
AssertionUtils.assert(false, new CoastException('custom coast exception'));
|
|
75
|
+
} catch (error) {
|
|
76
|
+
expect(error).toBeInstanceOf(CoastException);
|
|
77
|
+
safeExpect((error as CoastException).message).toEqual('custom coast exception');
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should not throw if value is truthy', () => {
|
|
82
|
+
safeExpect(() => AssertionUtils.assert(true)).not.toThrow();
|
|
83
|
+
safeExpect(() => AssertionUtils.assert(1)).not.toThrow();
|
|
84
|
+
safeExpect(() => AssertionUtils.assert('hello')).not.toThrow();
|
|
85
|
+
safeExpect(() => AssertionUtils.assert({})).not.toThrow();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should type narrow to exclude falsy', () => {
|
|
89
|
+
const x = 'hello' as false | string;
|
|
90
|
+
assertType<Equals<typeof x, false | string>>();
|
|
91
|
+
|
|
92
|
+
AssertionUtils.assert(x);
|
|
93
|
+
assertType<Equals<typeof x, string>>();
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('assertValidEntityReference', () => {
|
|
98
|
+
it('should throw if value is not defined', () => {
|
|
99
|
+
const x = undefined as object | undefined;
|
|
100
|
+
try {
|
|
101
|
+
AssertionUtils.assertValidEntityReference(x, EntityType.WORKFLOW_ENTITY);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
expect(error).toBeInstanceOf(InvalidEntityReferenceException);
|
|
104
|
+
|
|
105
|
+
safeExpect((error as InvalidEntityReferenceException).message).toEqual(
|
|
106
|
+
`Invalid entity reference: ${EntityTypeLabels[EntityType.WORKFLOW_ENTITY]} not found`
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
safeExpect((error as InvalidEntityReferenceException).additionalData).toMatchObject({
|
|
110
|
+
entityType: EntityType.WORKFLOW_ENTITY,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should use custom error message', () => {
|
|
116
|
+
const x = undefined as object | undefined;
|
|
117
|
+
try {
|
|
118
|
+
AssertionUtils.assertValidEntityReference(x, EntityType.WORKFLOW_ENTITY, {
|
|
119
|
+
message: 'x should exist...',
|
|
120
|
+
id: 'abc-123',
|
|
121
|
+
});
|
|
122
|
+
} catch (error) {
|
|
123
|
+
expect(error).toBeInstanceOf(InvalidEntityReferenceException);
|
|
124
|
+
safeExpect((error as InvalidEntityReferenceException).message).toEqual('x should exist...');
|
|
125
|
+
|
|
126
|
+
safeExpect((error as InvalidEntityReferenceException).additionalData).toMatchObject({
|
|
127
|
+
entityType: EntityType.WORKFLOW_ENTITY,
|
|
128
|
+
id: 'abc-123',
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should not throw and should type narrow if value is defined', () => {
|
|
134
|
+
const x = { id: 'abc' } as object | undefined;
|
|
135
|
+
assertType<Equals<typeof x, object | undefined>>();
|
|
136
|
+
|
|
137
|
+
AssertionUtils.assertValidEntityReference(x, EntityType.COMPONENT);
|
|
138
|
+
assertType<Equals<typeof x, object>>();
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
package/tsconfig.json
CHANGED
|
@@ -3,7 +3,15 @@
|
|
|
3
3
|
"compilerOptions": {
|
|
4
4
|
"composite": true,
|
|
5
5
|
"outDir": "./dist",
|
|
6
|
-
"rootDir": "./src"
|
|
6
|
+
"rootDir": "./src",
|
|
7
|
+
"paths": {
|
|
8
|
+
"@coast/core-types/*": ["../core-types/src/*"],
|
|
9
|
+
"@coast/core-types": ["../core-types/src"]
|
|
10
|
+
}
|
|
7
11
|
},
|
|
8
|
-
"
|
|
12
|
+
"references": [
|
|
13
|
+
{ "path": "../core-types" }
|
|
14
|
+
],
|
|
15
|
+
"include": ["src/**/*"],
|
|
16
|
+
"exclude": ["node_modules", "dist"]
|
|
9
17
|
}
|