@dungarees/core 0.11.6 → 0.12.0

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/package.json CHANGED
@@ -24,72 +24,44 @@
24
24
  "hotscript": "^1.0.13",
25
25
  "rxjs": "^7.8.1"
26
26
  },
27
- "version": "0.11.6",
27
+ "peerDependencies": {
28
+ "rxjs-marbles": "^7.0.1",
29
+ "vitest": "^3.0.2"
30
+ },
31
+ "version": "0.12.0",
28
32
  "exports": {
29
33
  "./application.ts": {
30
34
  "import": "./application.js",
31
35
  "types": "./application.d.ts"
32
36
  },
33
- "./error.test.ts": {
34
- "import": "./error.test.js",
35
- "types": "./error.test.d.ts"
36
- },
37
37
  "./error.ts": {
38
38
  "import": "./error.js",
39
39
  "types": "./error.d.ts"
40
40
  },
41
- "./event.test.ts": {
42
- "import": "./event.test.js",
43
- "types": "./event.test.d.ts"
44
- },
45
41
  "./event.ts": {
46
42
  "import": "./event.js",
47
43
  "types": "./event.d.ts"
48
44
  },
49
- "./fake.test.ts": {
50
- "import": "./fake.test.js",
51
- "types": "./fake.test.d.ts"
52
- },
53
45
  "./fake.ts": {
54
46
  "import": "./fake.js",
55
47
  "types": "./fake.d.ts"
56
48
  },
57
- "./marbles-vitest.test.ts": {
58
- "import": "./marbles-vitest.test.js",
59
- "types": "./marbles-vitest.test.d.ts"
60
- },
61
49
  "./marbles-vitest.ts": {
62
50
  "import": "./marbles-vitest.js",
63
51
  "types": "./marbles-vitest.d.ts"
64
52
  },
65
- "./marbles.test.ts": {
66
- "import": "./marbles.test.js",
67
- "types": "./marbles.test.d.ts"
68
- },
69
53
  "./marbles.ts": {
70
54
  "import": "./marbles.js",
71
55
  "types": "./marbles.d.ts"
72
56
  },
73
- "./type-util.test.ts": {
74
- "import": "./type-util.test.js",
75
- "types": "./type-util.test.d.ts"
76
- },
77
57
  "./type-util.ts": {
78
58
  "import": "./type-util.js",
79
59
  "types": "./type-util.d.ts"
80
60
  },
81
- "./url.test.ts": {
82
- "import": "./url.test.js",
83
- "types": "./url.test.d.ts"
84
- },
85
61
  "./url.ts": {
86
62
  "import": "./url.js",
87
63
  "types": "./url.d.ts"
88
64
  },
89
- "./util.test.ts": {
90
- "import": "./util.test.js",
91
- "types": "./util.test.d.ts"
92
- },
93
65
  "./util.ts": {
94
66
  "import": "./util.js",
95
67
  "types": "./util.d.ts"
package/url.d.ts CHANGED
@@ -9,5 +9,4 @@ export type UrlConfig = {
9
9
  export type UrlSearchConfig = Record<string, number | string | boolean>;
10
10
  export declare const stringifyUrl: (config: UrlConfig) => string;
11
11
  export declare const parseUrl: (url: `${string}://${string}`) => UrlConfig;
12
- export type Split<STRING, CHARACTER extends string> = STRING extends `${infer S1}${CHARACTER}${infer S2}` ? [S1, S2] : never;
13
12
  export type Url = string;
package/error.test.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/error.test.js DELETED
@@ -1,72 +0,0 @@
1
- import { createCausedError, getErrorMessage, getThrownError, isAbortError, isNetworkError, } from './error.js';
2
- import { expect, test } from 'vitest';
3
- test('getErrorMessage reads the message off an Error', () => {
4
- expect(getErrorMessage(new Error('it broke'))).toBe('it broke');
5
- });
6
- test('getErrorMessage stringifies anything else that was thrown', () => {
7
- expect(getErrorMessage('a bare string')).toBe('a bare string');
8
- expect(getErrorMessage(undefined)).toBe('undefined');
9
- expect(getErrorMessage(404)).toBe('404');
10
- });
11
- test('getErrorMessage reads a subclass like any other Error', () => {
12
- class ParseError extends Error {
13
- }
14
- expect(getErrorMessage(new ParseError('bad json'))).toBe('bad json');
15
- });
16
- test('createCausedError prefixes the message of the error it is given', () => {
17
- expect(createCausedError({ message: 'Invalid package.json', cause: new Error('bad json') }).message).toBe('Invalid package.json: bad json');
18
- });
19
- test('createCausedError keeps the original as the cause, so the chain survives', () => {
20
- const original = new Error('bad json');
21
- expect(createCausedError({ message: 'Invalid package.json', cause: original }).cause).toBe(original);
22
- });
23
- test('createCausedError works on a non-Error cause without losing it', () => {
24
- const caused = createCausedError({ message: 'Invalid package.json', cause: 'thrown string' });
25
- expect(caused.message).toBe('Invalid package.json: thrown string');
26
- expect(caused.cause).toBe('thrown string');
27
- });
28
- test('getThrownError hands back the Error that was thrown, cause and all', () => {
29
- const cause = new Error('bad literal');
30
- const thrown = getThrownError(() => {
31
- throw new Error('Invalid type in store', { cause });
32
- });
33
- expect(thrown.message).toBe('Invalid type in store');
34
- expect(thrown.cause).toBe(cause);
35
- });
36
- test('getThrownError fails when nothing is thrown, rather than returning undefined', () => {
37
- expect(() => getThrownError(() => 'no throw here')).toThrow('Expected a throw');
38
- });
39
- test('getThrownError fails when the thrown value is not an Error', () => {
40
- const notAnError = 'a bare string';
41
- expect(() => getThrownError(() => {
42
- throw notAnError;
43
- })).toThrow('Expected an Error to be thrown, got: a bare string');
44
- });
45
- test('isAbortError recognises the DOMException a real abort produces', () => {
46
- const controller = new AbortController();
47
- controller.abort();
48
- expect(isAbortError(controller.signal.reason)).toBe(true);
49
- });
50
- test('isAbortError recognises an error that only names AbortError in its message', () => {
51
- expect(isAbortError(new Error('Fetch failed: AbortError'))).toBe(true);
52
- });
53
- test('isAbortError rejects an ordinary error', () => {
54
- expect(isAbortError(new Error('it broke'))).toBe(false);
55
- });
56
- test('isAbortError rejects values that carry no name or message at all', () => {
57
- expect(isAbortError(null)).toBe(false);
58
- expect(isAbortError(undefined)).toBe(false);
59
- expect(isAbortError('AbortError')).toBe(false);
60
- });
61
- test('isNetworkError recognises the TypeError a failed fetch throws', () => {
62
- expect(isNetworkError(new TypeError('Load failed'))).toBe(true);
63
- });
64
- test('isNetworkError rejects a TypeError thrown for any other reason', () => {
65
- expect(isNetworkError(new TypeError('x is not a function'))).toBe(false);
66
- });
67
- test('isNetworkError rejects a matching message on an error that is not a TypeError', () => {
68
- expect(isNetworkError(new Error('Load failed'))).toBe(false);
69
- });
70
- test('isNetworkError rejects a nullish value', () => {
71
- expect(isNetworkError(null)).toBe(false);
72
- });
package/event.test.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/event.test.js DELETED
@@ -1,22 +0,0 @@
1
- import { createEventCreators } from './event.js';
2
- import { expect, expectTypeOf, test } from 'vitest';
3
- test('DomainEventOf derives the discriminated union from the payload map', () => {
4
- expectTypeOf().toEqualTypeOf();
5
- });
6
- test('createEventCreators builds a creator that emits its event type and payload', () => {
7
- const creators = createEventCreators();
8
- expect(creators.greet({ name: 'Ada' })).toEqual({ type: 'greet', payload: { name: 'Ada' } });
9
- });
10
- test('createEventCreators converts kebab-case event types to camelCase creator names', () => {
11
- const creators = createEventCreators();
12
- expect(creators.taskDone({ id: '7' })).toEqual({ type: 'task-done', payload: { id: '7' } });
13
- });
14
- test('createEventCreators makes an undefined-payload creator take no argument', () => {
15
- const creators = createEventCreators();
16
- expect(creators.done()).toEqual({ type: 'done', payload: undefined });
17
- });
18
- test('createEventCreators types each creator from the payload map', () => {
19
- const creators = createEventCreators();
20
- expectTypeOf(creators.taskDone).toEqualTypeOf();
21
- expectTypeOf(creators.done).toEqualTypeOf();
22
- });
package/fake.test.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/fake.test.js DELETED
@@ -1,61 +0,0 @@
1
- import { addErrorMethodsToFake } from './fake.js';
2
- import { coreMarbles } from '@dungarees/core/marbles-vitest.ts';
3
- import { of } from 'rxjs';
4
- import { expect, test } from 'vitest';
5
- test('Create the original if args are empty', () => {
6
- const originalFake = () => ({ method: () => 1 });
7
- const fakeCreator = addErrorMethodsToFake(originalFake);
8
- const fake = fakeCreator();
9
- expect(fake.method).not.toThrow();
10
- });
11
- test('Create sync throwing function', () => {
12
- const originalFake = () => ({ method: () => 1 });
13
- const fakeCreator = addErrorMethodsToFake(originalFake);
14
- const error = new Error('test error');
15
- const fake = fakeCreator({ method: { type: 'sync', error } });
16
- expect(fake.method).toThrow(error);
17
- });
18
- test('Create multiple sync throwing function', () => {
19
- const originalFake = () => ({ method: () => 1, method2: () => 2 });
20
- const fakeCreator = addErrorMethodsToFake(originalFake);
21
- const error = new Error('test error');
22
- const error2 = new Error('test error2');
23
- const fake = fakeCreator({
24
- method: { type: 'sync', error },
25
- method2: { type: 'sync', error: error2 },
26
- });
27
- expect(fake.method).toThrow(error);
28
- expect(fake.method2).toThrow(error2);
29
- });
30
- test('Create async throwing function', async () => {
31
- const originalFake = () => ({ method: async () => 1 });
32
- const fakeCreator = addErrorMethodsToFake(originalFake);
33
- const error = new Error('test error');
34
- const fake = fakeCreator({ method: { type: 'async', error } });
35
- await expect(fake.method).rejects.toEqual(error);
36
- });
37
- test('Create observable throwing function', coreMarbles((m) => {
38
- const originalFake = () => ({ method: () => of(1) });
39
- const fakeCreator = addErrorMethodsToFake(originalFake);
40
- const error = new Error('test error');
41
- const fake = fakeCreator({ method: { type: 'observable', error } });
42
- m.expect(fake.method()).toBeObservable('-#', {}, error);
43
- }));
44
- test('Forwarding constructor paramters', () => {
45
- const originalFake = (num1, num2) => ({
46
- method: () => num1,
47
- method2: () => num2,
48
- });
49
- const fakeCreator = addErrorMethodsToFake(originalFake);
50
- const fake = fakeCreator({}, 1, 2);
51
- expect(fake.method()).toBe(1);
52
- expect(fake.method2()).toBe(2);
53
- });
54
- test('A throwing method stays callable with the arguments the original took', () => {
55
- const originalFake = () => ({ method: (_, count) => count });
56
- const fakeCreator = addErrorMethodsToFake(originalFake);
57
- expect(fakeCreator().method('a', 1)).toBe(1);
58
- const error = new Error('boom');
59
- const fake = fakeCreator({ method: { type: 'sync', error } });
60
- expect(() => fake.method('a', 1)).toThrow(error);
61
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,116 +0,0 @@
1
- import { configure, coreMarbles, mtest } from './marbles-vitest.js';
2
- import { Subject } from 'rxjs';
3
- import { expect, test } from 'vitest';
4
- test('it should run a single marble', coreMarbles(({ expect, cold }) => {
5
- expect(cold('a')).toBeObservable('a', { a: 'a' });
6
- }));
7
- test.each([
8
- ['tf', 'tf'],
9
- ['ft', 'ft'],
10
- ])('it should work with each', coreMarbles(({ expect, coldBoolean }, a, b) => {
11
- expect(coldBoolean(a)).toBeObservableBoolean(b);
12
- }));
13
- mtest.each([
14
- ['tf', 'tf'],
15
- ['ft', 'ft'],
16
- ])('mtest should work with each', ({ expect, coldBoolean }, a, b) => {
17
- expect(coldBoolean(a)).toBeObservableBoolean(b);
18
- });
19
- mtest('it should run without the wrapper', ({ expect, coldBoolean }) => {
20
- expect(coldBoolean('tf')).toBeObservableBoolean('tf');
21
- });
22
- mtest('it should run a single function', ({ expect, coldCall }) => {
23
- const s = new Subject();
24
- coldCall('-cc', {
25
- c: () => {
26
- s.next('c');
27
- },
28
- });
29
- expect(s).toBeObservable('-cc', { c: 'c' });
30
- });
31
- mtest('it should run multiple functions', ({ expect, coldCall }) => {
32
- const s = new Subject();
33
- coldCall('-cd', {
34
- c: () => {
35
- s.next('c');
36
- },
37
- d: () => {
38
- s.next('d');
39
- },
40
- });
41
- expect(s).toBeObservable('-cd', { c: 'c', d: 'd' });
42
- });
43
- mtest('it should create a boolean marble', ({ expect, coldBoolean }) => {
44
- expect(coldBoolean('tf')).toBeObservable('tf', { t: true, f: false });
45
- });
46
- mtest('it should assert a boolean marble', ({ expect, cold }) => {
47
- expect(cold('tf', { t: true, f: false })).toBeObservableBoolean('tf');
48
- });
49
- mtest('it should create a cold marble with a value', ({ expect, coldValue }) => {
50
- expect(coldValue('-v', true)).toBeObservableBoolean('-t');
51
- });
52
- mtest('it should create a cold marble with a value or undefined', ({ expect, coldValueOrUndefined }) => {
53
- expect(coldValueOrUndefined('-v0', true)).toBeObservable('-t0', {
54
- t: true,
55
- '0': undefined,
56
- });
57
- });
58
- mtest('it should create a cold marble with a value step', ({ expect, coldStep }) => {
59
- expect(coldStep(true)).toBeObservableBoolean('-t');
60
- expect(coldStep(true, 2)).toBeObservableBoolean('--t');
61
- });
62
- mtest('it should create a cold marble with a value step and close', ({ expect, coldStepAndClose }) => {
63
- expect(coldStepAndClose(true)).toBeObservableBoolean('-(t|)');
64
- expect(coldStepAndClose(true, 2)).toBeObservableBoolean('--(t|)');
65
- });
66
- mtest('it should create a cold marble with an error', ({ expect, coldError }) => {
67
- expect(coldError(new Error('test error'))).toBeObservable('-#', {}, new Error('test error'));
68
- expect(coldError(new Error('test error'), 2)).toBeObservable('--#', {}, new Error('test error'));
69
- });
70
- mtest('it should create a cold marble with a value and error', ({ expect, coldStepAndError }) => {
71
- expect(coldStepAndError(true, new Error('test error'))).toBeObservable('-(t#)', { t: true }, new Error('test error'));
72
- expect(coldStepAndError(true, new Error('test error'), 2)).toBeObservable('--(t#)', { t: true }, new Error('test error'));
73
- });
74
- mtest('it should assert a value marble', ({ expect, coldStep }) => {
75
- expect(coldStep(true)).toBeObservableValue('-v', true);
76
- });
77
- mtest('it should assert a value marble default pattern', ({ expect, coldStep }) => {
78
- expect(coldStep(true, 0)).toBeObservableValue(true);
79
- });
80
- mtest('it should assert a value and close marble', ({ expect, coldStepAndClose }) => {
81
- expect(coldStepAndClose(true, 0)).toBeObservableValueAndClose(true);
82
- });
83
- mtest('it should assert a value and close marble', ({ expect, coldStepAndError }) => {
84
- expect(coldStepAndError(true, new Error('test error'), 0)).toBeObservableValueAndError(true, new Error('test error'));
85
- });
86
- mtest('it should assert a value marble or undefined', ({ expect, coldValueOrUndefined }) => {
87
- expect(coldValueOrUndefined('-v0', true)).toBeObservableValueOrUndefined('-v0', true);
88
- });
89
- mtest('it should assert a step', ({ expect, coldStep }) => {
90
- expect(coldStep(true)).toBeObservableStep(true);
91
- expect(coldStep(true, 2)).toBeObservableStep(true, 2);
92
- });
93
- mtest('it should assert a step and close', ({ expect, coldStepAndClose }) => {
94
- expect(coldStepAndClose(true)).toBeObservableStepAndClose(true);
95
- expect(coldStepAndClose(true, 2)).toBeObservableStepAndClose(true, 2);
96
- });
97
- mtest('it should assert an error', ({ expect, coldError }) => {
98
- expect(coldError(new Error('test error'))).toBeObservableError(new Error('test error'));
99
- expect(coldError(new Error('test error'), 2)).toBeObservableError(new Error('test error'), 2);
100
- });
101
- mtest('it should assert a step with an error', ({ expect, coldStepAndError }) => {
102
- expect(coldStepAndError(true, new Error('test error'))).toBeObservableStepAndError(true, new Error('test error'));
103
- expect(coldStepAndError(true, new Error('test error'), 2)).toBeObservableStepAndError(true, new Error('test error'), 2);
104
- });
105
- const { cases } = configure({});
106
- const casesThatRan = [];
107
- cases('skip and only flags', (_m, { name }) => {
108
- casesThatRan.push(name);
109
- }, [
110
- { name: 'plain case' },
111
- { name: 'case flagged skip', skip: true },
112
- { name: 'case with skip false', skip: false },
113
- ]);
114
- test('cases runs every case except the ones flagged skip', () => {
115
- expect(casesThatRan).toEqual(['plain case', 'case with skip false']);
116
- });
package/marbles.test.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/marbles.test.js DELETED
@@ -1,36 +0,0 @@
1
- import { coreMarbles } from '@dungarees/core/marbles.ts';
2
- import { Subject } from 'rxjs';
3
- import { test } from 'vitest';
4
- test('it should run a single function', coreMarbles(({ expect, coldCall }) => {
5
- const s = new Subject();
6
- coldCall('-cc', {
7
- c: () => {
8
- s.next('c');
9
- },
10
- });
11
- expect(s).toBeObservable('-cc', { c: 'c' });
12
- }));
13
- test('it should run multiple functions', coreMarbles(({ expect, coldCall }) => {
14
- const s = new Subject();
15
- coldCall('-cd', {
16
- c: () => {
17
- s.next('c');
18
- },
19
- d: () => {
20
- s.next('d');
21
- },
22
- });
23
- expect(s).toBeObservable('-cd', { c: 'c', d: 'd' });
24
- }));
25
- test('it should create a boolean marble', coreMarbles(({ expect, coldBoolean }) => {
26
- expect(coldBoolean('tf')).toBeObservable('tf', { t: true, f: false });
27
- }));
28
- test('it should assert a boolean marble', coreMarbles(({ expect, cold }) => {
29
- expect(cold('tf', { t: true, f: false })).toBeObservableBoolean('tf');
30
- }));
31
- test.each([
32
- ['tf', 'tf'],
33
- ['ft', 'ft'],
34
- ])('it should work with each', coreMarbles(({ expect, coldBoolean }, a, b) => {
35
- expect(coldBoolean(a)).toBeObservableBoolean(b);
36
- }));
@@ -1 +0,0 @@
1
- export {};
package/type-util.test.js DELETED
@@ -1,147 +0,0 @@
1
- import { expect, expectTypeOf, test } from 'vitest';
2
- test('Split<PATH, DELIMITER>', () => {
3
- expectTypeOf().toEqualTypeOf();
4
- expectTypeOf().toEqualTypeOf();
5
- expectTypeOf().toEqualTypeOf();
6
- });
7
- test('SplitObjectPath<PATH>', () => {
8
- expectTypeOf().toEqualTypeOf();
9
- expectTypeOf().toEqualTypeOf();
10
- expectTypeOf().toEqualTypeOf();
11
- });
12
- test('SplitFilePath<PATH>', () => {
13
- expectTypeOf().toEqualTypeOf();
14
- expectTypeOf().toEqualTypeOf();
15
- expectTypeOf().toEqualTypeOf();
16
- });
17
- test('StringLiteral<LITERAL>', () => {
18
- const literal = 'asd';
19
- expectTypeOf(literal).toEqualTypeOf();
20
- // Widened through an annotation rather than an `as` cast, so rule 4 still holds.
21
- const widened = 'asd';
22
- // @ts-expect-error it has to be a literal
23
- const nonLiteral = widened;
24
- expectTypeOf(nonLiteral).toEqualTypeOf();
25
- });
26
- test('ObjectWithStringLiteralKey<KEY, VALUE>', () => {
27
- const obj = {
28
- a: 1,
29
- };
30
- expectTypeOf(obj).toEqualTypeOf();
31
- // @ts-expect-error it has to be a literal
32
- const nonLiteral = {
33
- a: 1,
34
- };
35
- expectTypeOf(nonLiteral).toEqualTypeOf();
36
- });
37
- test('JsonType', () => {
38
- const json = {
39
- a: 1,
40
- b: '2',
41
- c: true,
42
- d: null,
43
- e: [1, '2', true, null, [1, '2', true, null]],
44
- };
45
- expect(json).toBeDefined();
46
- // @ts-expect-error it cannot be a function
47
- const nonJson = {
48
- f: () => { },
49
- };
50
- expect(nonJson).toBeDefined();
51
- });
52
- test('TokenNonEmptyString<TOKEN>', () => {
53
- const token = 'a';
54
- expectTypeOf(token).toEqualTypeOf();
55
- // @ts-expect-error it cannot be empty
56
- const nonToken = '';
57
- expectTypeOf(nonToken).toEqualTypeOf();
58
- });
59
- test('Guard<TYPE>', () => {
60
- const guard = (arg) => arg === 1;
61
- expectTypeOf(guard).toEqualTypeOf();
62
- // @ts-expect-error it has to be a guard
63
- const nonGuard = (arg) => arg === 1;
64
- expectTypeOf(nonGuard).toEqualTypeOf();
65
- });
66
- test('GetGuarded<GUARD>', () => {
67
- const testUnused_guard = (arg) => arg === 1;
68
- expectTypeOf().toEqualTypeOf();
69
- });
70
- test('EntryTuples', () => {
71
- expectTypeOf().toEqualTypeOf();
72
- expectTypeOf().toEqualTypeOf();
73
- expectTypeOf().toEqualTypeOf();
74
- expectTypeOf().toEqualTypeOf();
75
- });
76
- test('FilterRecord<RECORD, TYPE>', () => {
77
- expectTypeOf().toEqualTypeOf();
78
- });
79
- test('GetAllPaths<OBJECT>', () => {
80
- expectTypeOf().toEqualTypeOf();
81
- });
82
- test('GetValuesByPath<OBJECT, PATH>', () => {
83
- expectTypeOf().toEqualTypeOf();
84
- });
85
- test('JoinArray<STRINGS, DELIMITER>', () => {
86
- expectTypeOf().toEqualTypeOf();
87
- expectTypeOf().toEqualTypeOf();
88
- });
89
- test('FromCamelCase<STRING>', () => {
90
- expectTypeOf().toEqualTypeOf();
91
- expectTypeOf().toEqualTypeOf();
92
- expectTypeOf().toEqualTypeOf();
93
- });
94
- test('ToCamelCase<STRING[]>', () => {
95
- expectTypeOf().toEqualTypeOf();
96
- expectTypeOf().toEqualTypeOf();
97
- });
98
- test('FromKebabCase<STRING>', () => {
99
- expectTypeOf().toEqualTypeOf();
100
- expectTypeOf().toEqualTypeOf();
101
- expectTypeOf().toEqualTypeOf();
102
- });
103
- test('ToKebabCase<STRING[]>', () => {
104
- expectTypeOf().toEqualTypeOf();
105
- expectTypeOf().toEqualTypeOf();
106
- });
107
- test('FromSnakeCase<STRING>', () => {
108
- expectTypeOf().toEqualTypeOf();
109
- expectTypeOf().toEqualTypeOf();
110
- expectTypeOf().toEqualTypeOf();
111
- });
112
- test('ToSnakeCase<STRING[]>', () => {
113
- expectTypeOf().toEqualTypeOf();
114
- expectTypeOf().toEqualTypeOf();
115
- });
116
- test('Mutable<TYPE>', () => {
117
- expectTypeOf().toEqualTypeOf();
118
- expectTypeOf().toEqualTypeOf();
119
- });
120
- test('FlattenIntersection<OBJECT>', () => {
121
- expectTypeOf().toEqualTypeOf();
122
- expectTypeOf().toEqualTypeOf();
123
- });
124
- test('PartialBesides<OBJECT, KEYS>', () => {
125
- // Flattened first: PartialBesides produces an intersection, and expectTypeOf compares that
126
- // by its parts rather than by the object it is equivalent to.
127
- expectTypeOf().toEqualTypeOf();
128
- });
129
- test('DeepPartial<T> - single level', () => {
130
- expectTypeOf().toEqualTypeOf();
131
- });
132
- test('DeepPartial<T> - nested props', () => {
133
- expectTypeOf().toEqualTypeOf();
134
- });
135
- test('SyncFunctionToAsync<FUNC>', () => {
136
- expectTypeOf().toEqualTypeOf();
137
- });
138
- test('SyncFunctionToAsync<FUNC> accepts every function shape', () => {
139
- expectTypeOf().toEqualTypeOf();
140
- expectTypeOf().toEqualTypeOf();
141
- expectTypeOf().toEqualTypeOf();
142
- });
143
- test('DetachableMethods<OBJECT>', () => {
144
- expectTypeOf().toEqualTypeOf();
145
- expectTypeOf().toEqualTypeOf();
146
- expectTypeOf().toEqualTypeOf();
147
- });
package/url.test.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/url.test.js DELETED
@@ -1,48 +0,0 @@
1
- import { parseUrl, stringifyUrl } from './url.js';
2
- import { expect, test } from 'vitest';
3
- test('stringify full url', () => {
4
- expect(stringifyUrl({
5
- protocol: 'https',
6
- hostname: 'localhost',
7
- pathname: '/path',
8
- port: 8080,
9
- search: {
10
- a: '1',
11
- b: '2',
12
- },
13
- hash: 'hash',
14
- })).toBe('https://localhost:8080/path?a=1&b=2#hash');
15
- });
16
- test('stringify partial url', () => {
17
- expect(stringifyUrl({
18
- protocol: 'https',
19
- hostname: 'localhost',
20
- })).toBe('https://localhost/');
21
- });
22
- test('parse full url', () => {
23
- expect(parseUrl('https://localhost:8080/path?a=1&b=2#hash')).toEqual({
24
- protocol: 'https',
25
- hostname: 'localhost',
26
- pathname: '/path',
27
- port: 8080,
28
- search: {
29
- a: '1',
30
- b: '2',
31
- },
32
- hash: 'hash',
33
- });
34
- });
35
- test('parse full url', () => {
36
- expect(parseUrl('https://localhost/')).toEqual({
37
- protocol: 'https',
38
- hostname: 'localhost',
39
- pathname: '/',
40
- port: 80,
41
- search: {},
42
- hash: '',
43
- });
44
- });
45
- test('Url type', () => {
46
- const url = 'https://host:8080/path/subpath/?a=1&b=2#hash';
47
- expect(url).toBe(url);
48
- });
package/util.test.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/util.test.js DELETED
@@ -1,419 +0,0 @@
1
- import { assertDefined, assertImpossible, assertPredicate, assertTypeByGuard, boolFromThrow, boolFromThrowAsync, camelCase2kebabCase, capitalize, deepEqualPartial, findByPattern, isDeepEqual, isDefined, join, kebabCase2camelCase, makeObjectFromStringLiteral, mapConst, mapConstKeysToEntries, mapObjectFromKeys, objectFromConstEntries, optionalPatternToList, pluralize, split, unPrototypeProperties, } from './util.js';
2
- import { expect, expectTypeOf, test } from 'vitest';
3
- test('makeObjectFromStringLiteral', () => {
4
- const obj = makeObjectFromStringLiteral('key', 1);
5
- expect(obj['key']).toBe(1);
6
- });
7
- test('split is working in a typesafe way', () => {
8
- const splitted = split('a.a.a', '.');
9
- expectTypeOf().toEqualTypeOf();
10
- expect(splitted).toEqual(['a', 'a', 'a']);
11
- });
12
- test('join is working in a typesafe way', () => {
13
- const joined = join(['a', 'a', 'a'], '.');
14
- expectTypeOf().toEqualTypeOf();
15
- expect(joined).toBe('a.a.a');
16
- });
17
- test('capitalize', () => {
18
- const capitalized = capitalize('apple');
19
- expectTypeOf().toEqualTypeOf();
20
- expect(capitalized).toBe('Apple');
21
- });
22
- test('pluralize', () => {
23
- expect(pluralize('dog', -2)).toBe('dogs');
24
- expect(pluralize('dog', -1)).toBe('dog');
25
- expect(pluralize('dog', 0)).toBe('dogs');
26
- expect(pluralize('dog', 1)).toBe('dog');
27
- expect(pluralize('dog', 2)).toBe('dogs');
28
- expect(pluralize('dog', 1, true)).toBe('1 dog');
29
- expect(pluralize('dog', 2, true)).toBe('2 dogs');
30
- });
31
- test('kebabCase2camelCase', () => {
32
- const kebabCase = 'first-second-third';
33
- const camelCase = 'firstSecondThird';
34
- const output = kebabCase2camelCase(kebabCase);
35
- expect(output).toBe(camelCase);
36
- expectTypeOf().toEqualTypeOf();
37
- });
38
- test('camelCase2kebabCase', () => {
39
- const kebabCase = 'first-second-third';
40
- const camelCase = 'firstSecondThird';
41
- const output = camelCase2kebabCase(camelCase);
42
- expect(output).toBe(kebabCase);
43
- expectTypeOf().toEqualTypeOf();
44
- });
45
- test('deepEqualPartial', () => {
46
- expect(deepEqualPartial({}, {})).toBe(true);
47
- expect(deepEqualPartial(true, true)).toBe(true);
48
- expect(deepEqualPartial(true, false)).toBe(false);
49
- expect(deepEqualPartial({ baz: 54 }, { foo: 'bar', baz: 54 })).toBe(true);
50
- expect(deepEqualPartial({ baz: 55 }, { foo: 'bar', baz: 54 })).toBe(false);
51
- expect(deepEqualPartial({ foo: { baz: 'bar' } }, { foo: { baz: 'bar' }, quux: 'kill me' })).toBe(true);
52
- expect(deepEqualPartial({ foo: { baz: 'baz' } }, { foo: { baz: 'bar' }, quux: 'kill me' })).toBe(false);
53
- });
54
- test('deepEqualPartial treats a null expected as unequal rather than throwing', () => {
55
- expect(deepEqualPartial({ baz: 54 }, null)).toBe(false);
56
- expect(deepEqualPartial({ baz: 54 }, undefined)).toBe(false);
57
- expect(deepEqualPartial(null, null)).toBe(true);
58
- });
59
- test('findByPattern', () => {
60
- const value1 = findByPattern([], '');
61
- expectTypeOf().toEqualTypeOf();
62
- expect(value1).toBeUndefined();
63
- // @ts-expect-error itemToMatch has to follow the pattern type
64
- findByPattern([], {});
65
- // @ts-expect-error itemToMatch type has to be a serializable type
66
- const _ = (findByPattern);
67
- expect(_).toBeDefined();
68
- const value2 = findByPattern([{ pattern: 'ab', value: 1 }], 'ab');
69
- expectTypeOf().toEqualTypeOf();
70
- expect(value2).toBe(1);
71
- const value3 = findByPattern([{ pattern: 'ab', value: 1 }], 'no-match');
72
- expect(value3).toBe(undefined);
73
- const value4 = findByPattern([{ pattern: { a: 1 }, value: 1 }], { a: 1 });
74
- expect(value4).toBe(1);
75
- const value5 = findByPattern([{ value: 1 }], 'ab');
76
- expect(value5).toBe(1);
77
- const value6 = findByPattern([{ patternPartial: { a: 2 }, value: 1 }], { a: 1, b: 1 });
78
- expect(value6).toBe(undefined);
79
- const value7 = findByPattern([{ patternPartial: { a: 1 }, value: 1 }], { a: 1, b: 1 });
80
- expect(value7).toBe(1);
81
- const value8 = findByPattern([
82
- {
83
- patternPartial: { a: 1 },
84
- value: 1,
85
- },
86
- {
87
- pattern: { a: 1, b: 1 },
88
- value: 2,
89
- },
90
- ], { a: 1, b: 1 });
91
- expect(value8).toBe(2);
92
- const value9 = findByPattern([
93
- {
94
- value: 1,
95
- },
96
- {
97
- patternPartial: { a: 1 },
98
- value: 2,
99
- },
100
- {
101
- pattern: { a: 1, b: 1 },
102
- value: 3,
103
- },
104
- ], { a: 1, b: 1 });
105
- expect(value9).toBe(3);
106
- });
107
- test('optionalPatternToList', () => {
108
- const list1 = optionalPatternToList(1);
109
- expectTypeOf().toEqualTypeOf();
110
- expect(list1).toEqual([{ value: 1 }]);
111
- const list2 = optionalPatternToList([{ value: 1 }]);
112
- expectTypeOf().toEqualTypeOf();
113
- expect(list2).toEqual([{ value: 1 }]);
114
- expectTypeOf().toEqualTypeOf();
115
- });
116
- test('isDefined', () => {
117
- expect(isDefined(0)).toStrictEqual(true);
118
- expect(isDefined('')).toStrictEqual(true);
119
- expect(isDefined([])).toStrictEqual(true);
120
- expect(isDefined({})).toStrictEqual(true);
121
- expect(isDefined(undefined)).toStrictEqual(false);
122
- expect(isDefined(null)).toStrictEqual(false);
123
- });
124
- test('assertDefined', () => {
125
- expect(assertDefined(1, 'oops')).toBe(1);
126
- expect(() => assertDefined(undefined, 'oops')).toThrow('oops');
127
- expect(() => assertDefined(null, 'oops')).toThrow('oops');
128
- expect(() => assertDefined(undefined, (value) => `oops: ${value}`)).toThrow('oops: undefined');
129
- });
130
- test('assertTypeByGuard', () => {
131
- expect(assertTypeByGuard({
132
- value: 1,
133
- guard: (value) => typeof value === 'number',
134
- message: 'oops',
135
- })).toBe(1);
136
- expect(() => assertTypeByGuard({
137
- value: 'str',
138
- guard: (value) => typeof value === 'number',
139
- message: 'oops',
140
- })).toThrow('oops');
141
- expect(() => assertTypeByGuard({
142
- value: 'str',
143
- guard: (value) => typeof value === 'number',
144
- message: (value) => `oops: ${value}`,
145
- })).toThrow('oops: str');
146
- });
147
- test('assertPredicate', () => {
148
- const predicate = (value) => value > 0;
149
- expect(assertPredicate({ value: 1, predicate, message: 'oops' })).toBe(1);
150
- expect(() => assertPredicate({ value: -1, predicate, message: 'oops' })).toThrow('oops');
151
- expect(() => assertPredicate({ value: -1, predicate, message: (value) => `oops: ${value}` })).toThrow('oops: -1');
152
- });
153
- test('assertImpossible', () => {
154
- expect(() => assertImpossible('some message')).toThrow('some message');
155
- });
156
- test('unPrototypeProperties', () => {
157
- class Test {
158
- constructor(prop) {
159
- this.prop = prop;
160
- }
161
- method() {
162
- return this.prop;
163
- }
164
- method2() {
165
- return 'method2';
166
- }
167
- }
168
- const instance = new Test(1);
169
- const noPrototype = unPrototypeProperties(instance, ['method']);
170
- expectTypeOf().toEqualTypeOf();
171
- expect(noPrototype.method()).toBe(1);
172
- const method = noPrototype.method;
173
- expect(method()).toBe(1);
174
- expect(Object.hasOwn(noPrototype, 'method')).toBe(true);
175
- expect(Object.hasOwn(noPrototype, 'method2')).toBe(false);
176
- const clone = { ...noPrototype };
177
- expect(clone.method()).toBe(1);
178
- expect(Object.hasOwn(clone, 'method2')).toBe(false);
179
- // @ts-expect-error method3 is not a property of clone
180
- unPrototypeProperties(clone, ['method3']);
181
- });
182
- test('mapConst', () => {
183
- const input = ['a', 'b', 'c'];
184
- const output = mapConst(input)((value) => `${value}-const`);
185
- expectTypeOf().toEqualTypeOf();
186
- expect(output).toEqual(['a-const', 'b-const', 'c-const']);
187
- });
188
- test('mapConst expets a lambda with a correct return type', () => {
189
- const input = ['a', 'b', 'c'];
190
- // @ts-expect-error The return type of the lambda should depend on the input value
191
- mapConst(input)(() => 1);
192
- });
193
- test('mapConst infers input type from array', () => {
194
- const input = ['a', 'b', 'c'];
195
- const output = [];
196
- mapConst(input)((value, index) => {
197
- expectTypeOf().toEqualTypeOf();
198
- expectTypeOf(index).toEqualTypeOf();
199
- output.push(index);
200
- return `${value}-const`;
201
- });
202
- expect(output).toEqual([0, 1, 2]);
203
- });
204
- test('mapConst non-curried infers input type from array', () => {
205
- const input = ['a', 'b', 'c'];
206
- const output = [];
207
- const result = mapConst(input, (value, index) => {
208
- expectTypeOf().toEqualTypeOf();
209
- expectTypeOf(index).toEqualTypeOf();
210
- output.push(index);
211
- return 1;
212
- });
213
- expectTypeOf().toEqualTypeOf();
214
- expect(result).toEqual([1, 1, 1]);
215
- expect(output).toEqual([0, 1, 2]);
216
- });
217
- test('mapConstKeysToEntries infers input type from array', () => {
218
- const input = ['a', 'b', 'c'];
219
- const output = mapConstKeysToEntries(input)((value) => `${value}-const`);
220
- expectTypeOf().toEqualTypeOf();
221
- expect(output).toEqual([
222
- ['a', 'a-const'],
223
- ['b', 'b-const'],
224
- ['c', 'c-const'],
225
- ]);
226
- });
227
- test('mapConstKeysToEntries expets a lambda with a correct return type', () => {
228
- const input = ['a', 'b', 'c'];
229
- // @ts-expect-error The return type of the lambda should depend on the input value
230
- mapConstKeysToEntries(input)(() => 1);
231
- });
232
- test('mapConstKeysToEntries infers input type from array', () => {
233
- const input = ['a', 'b', 'c'];
234
- const output = [];
235
- const a = mapConstKeysToEntries(input, (value, index) => {
236
- expectTypeOf().toEqualTypeOf();
237
- expectTypeOf(index).toEqualTypeOf();
238
- output.push(index);
239
- return 1;
240
- });
241
- expectTypeOf().toEqualTypeOf();
242
- expect(a).toEqual([
243
- ['a', 1],
244
- ['b', 1],
245
- ['c', 1],
246
- ]);
247
- expect(output).toEqual([0, 1, 2]);
248
- });
249
- test('mapConstKeysToEntries infers input type from array', () => {
250
- const input = ['a', 'b', 'c'];
251
- const output = [];
252
- mapConstKeysToEntries(input)((value, index) => {
253
- expectTypeOf().toEqualTypeOf();
254
- expectTypeOf(index).toEqualTypeOf();
255
- output.push(index);
256
- return `${value}-const`;
257
- });
258
- expect(output).toEqual([0, 1, 2]);
259
- });
260
- test('objectFromConstEntries', () => {
261
- const entries = [
262
- ['a', 1],
263
- ['b', 2],
264
- ['c', 3],
265
- ];
266
- const obj = objectFromConstEntries(entries);
267
- expectTypeOf().toEqualTypeOf();
268
- expect(obj).toEqual({ a: 1, b: 2, c: 3 });
269
- });
270
- test('mapObjectFromKeys', () => {
271
- const keys = ['a', 'b', 'c'];
272
- const obj = mapObjectFromKeys(keys)((key, index) => {
273
- expectTypeOf().toEqualTypeOf();
274
- expectTypeOf(index).toEqualTypeOf();
275
- return `${key}-const`;
276
- });
277
- expectTypeOf().toEqualTypeOf();
278
- expect(obj).toEqual({ a: 'a-const', b: 'b-const', c: 'c-const' });
279
- });
280
- test('mapObjectFromKeys non-curried infers input type from array', () => {
281
- const keys = ['a', 'b', 'c'];
282
- const obj = mapObjectFromKeys(keys, (key, index) => {
283
- expectTypeOf().toEqualTypeOf();
284
- expectTypeOf(index).toEqualTypeOf();
285
- return 1;
286
- });
287
- expectTypeOf().toEqualTypeOf();
288
- expect(obj).toEqual({ a: 1, b: 1, c: 1 });
289
- });
290
- test('boolFromThrow returns true when function does not throw', () => {
291
- expect(boolFromThrow(() => { })).toBe(true);
292
- });
293
- test('boolFromThrow returns false when function throws', () => {
294
- expect(boolFromThrow(() => {
295
- throw new Error('fail');
296
- })).toBe(false);
297
- });
298
- test('boolFromThrowAsync returns true when async function does not throw', async () => {
299
- await expect(boolFromThrowAsync(async () => { })).resolves.toBe(true);
300
- });
301
- test('boolFromThrowAsync returns false when async function rejects', async () => {
302
- await expect(boolFromThrowAsync(async () => {
303
- throw new Error('fail');
304
- })).resolves.toBe(false);
305
- });
306
- test('isDeepEqual compares primitives by strict equality, with NaN equal to itself', () => {
307
- expect(isDeepEqual(1, 1)).toBe(true);
308
- expect(isDeepEqual(1, 2)).toBe(false);
309
- expect(isDeepEqual('a', 'a')).toBe(true);
310
- expect(isDeepEqual(1, '1')).toBe(false);
311
- expect(isDeepEqual(NaN, NaN)).toBe(true);
312
- expect(isDeepEqual(undefined, undefined)).toBe(true);
313
- expect(isDeepEqual(null, null)).toBe(true);
314
- expect(isDeepEqual(null, {})).toBe(false);
315
- expect(isDeepEqual({}, null)).toBe(false);
316
- });
317
- test('isDeepEqual compares plain objects by their own keys', () => {
318
- expect(isDeepEqual({ a: 1, b: 2 }, { a: 1, b: 2 })).toBe(true);
319
- expect(isDeepEqual({ a: 1 }, { a: 1, b: 2 })).toBe(false);
320
- expect(isDeepEqual({ a: 1, b: 2 }, { a: 1 })).toBe(false);
321
- expect(isDeepEqual({ a: { b: { c: 1 } } }, { a: { b: { c: 1 } } })).toBe(true);
322
- expect(isDeepEqual({ a: { b: { c: 1 } } }, { a: { b: { c: 2 } } })).toBe(false);
323
- });
324
- test('isDeepEqual compares arrays element-wise', () => {
325
- expect(isDeepEqual([1, 2, 3], [1, 2, 3])).toBe(true);
326
- expect(isDeepEqual([1, 2], [1, 2, 3])).toBe(false);
327
- expect(isDeepEqual([{ a: 1 }], [{ a: 1 }])).toBe(true);
328
- expect(isDeepEqual([{ a: 1 }], [{ a: 2 }])).toBe(false);
329
- expect(isDeepEqual([], [])).toBe(true);
330
- });
331
- test('isDeepEqual treats a different prototype as unequal', () => {
332
- class A {
333
- constructor(x) {
334
- this.x = x;
335
- }
336
- }
337
- class B {
338
- constructor(x) {
339
- this.x = x;
340
- }
341
- }
342
- expect(isDeepEqual(new A(1), new B(1))).toBe(false);
343
- expect(isDeepEqual([1], { 0: 1 })).toBe(false);
344
- });
345
- test('isDeepEqual compares Dates by time', () => {
346
- expect(isDeepEqual(new Date(1000), new Date(1000))).toBe(true);
347
- expect(isDeepEqual(new Date(1000), new Date(2000))).toBe(false);
348
- });
349
- test('isDeepEqual compares RegExps by source and flags', () => {
350
- expect(isDeepEqual(/ab+/g, /ab+/g)).toBe(true);
351
- expect(isDeepEqual(/ab+/g, /ab+/i)).toBe(false);
352
- expect(isDeepEqual(/ab+/g, /ac+/g)).toBe(false);
353
- });
354
- test('isDeepEqual compares Sets by size and membership', () => {
355
- expect(isDeepEqual(new Set([1, 2]), new Set([1, 2]))).toBe(true);
356
- expect(isDeepEqual(new Set([1, 2]), new Set([2, 1]))).toBe(true);
357
- expect(isDeepEqual(new Set([1, 2]), new Set([1, 3]))).toBe(false);
358
- expect(isDeepEqual(new Set([1]), new Set([1, 2]))).toBe(false);
359
- });
360
- test('isDeepEqual compares Maps by size and entries', () => {
361
- expect(isDeepEqual(new Map([['a', 1]]), new Map([['a', 1]]))).toBe(true);
362
- expect(isDeepEqual(new Map([['a', 1]]), new Map([['a', 2]]))).toBe(false);
363
- expect(isDeepEqual(new Map([['a', 1]]), new Map([['b', 1]]))).toBe(false);
364
- expect(isDeepEqual(new Map([['a', { b: 1 }]]), new Map([['a', { b: 1 }]]))).toBe(true);
365
- });
366
- test('isDeepEqual compares ArrayBuffers and typed arrays byte by byte', () => {
367
- const bufferOf = (bytes) => new Uint8Array(bytes).buffer;
368
- expect(isDeepEqual(bufferOf([1, 2, 3]), bufferOf([1, 2, 3]))).toBe(true);
369
- expect(isDeepEqual(bufferOf([1, 2, 3]), bufferOf([1, 2, 4]))).toBe(false);
370
- expect(isDeepEqual(bufferOf([1, 2]), bufferOf([1, 2, 3]))).toBe(false);
371
- expect(isDeepEqual(new Uint8Array([1, 2]), new Uint8Array([1, 2]))).toBe(true);
372
- expect(isDeepEqual(new Uint8Array([1, 2]), new Uint8Array([1, 3]))).toBe(false);
373
- expect(isDeepEqual(new DataView(bufferOf([9])), new DataView(bufferOf([9])))).toBe(true);
374
- expect(isDeepEqual(new DataView(bufferOf([9])), new DataView(bufferOf([8])))).toBe(false);
375
- });
376
- test('isDeepEqual survives circular references', () => {
377
- const a = { name: 'a' };
378
- a.self = a;
379
- const b = { name: 'a' };
380
- b.self = b;
381
- expect(isDeepEqual(a, b)).toBe(true);
382
- const c = { name: 'c' };
383
- c.self = c;
384
- expect(isDeepEqual(a, c)).toBe(false);
385
- });
386
- test('isDeepEqual prefers a custom valueOf when one is defined', () => {
387
- class Money {
388
- constructor(cents) {
389
- this.cents = cents;
390
- }
391
- valueOf() {
392
- return this.cents;
393
- }
394
- }
395
- expect(isDeepEqual(new Money(100), new Money(100))).toBe(true);
396
- expect(isDeepEqual(new Money(100), new Money(200))).toBe(false);
397
- });
398
- test('isDeepEqual falls back to a custom toString when one is defined', () => {
399
- class Tag {
400
- constructor(label) {
401
- this.label = label;
402
- }
403
- toString() {
404
- return this.label;
405
- }
406
- }
407
- expect(isDeepEqual(new Tag('x'), new Tag('x'))).toBe(true);
408
- expect(isDeepEqual(new Tag('x'), new Tag('y'))).toBe(false);
409
- });
410
- test('isDeepEqual compares subclasses of built-ins by their built-in semantics', () => {
411
- class MySet extends Set {
412
- }
413
- class MyMap extends Map {
414
- }
415
- expect(isDeepEqual(new MySet([1]), new MySet([1]))).toBe(true);
416
- expect(isDeepEqual(new MySet([1]), new MySet([2]))).toBe(false);
417
- expect(isDeepEqual(new MyMap([['a', 1]]), new MyMap([['a', 1]]))).toBe(true);
418
- expect(isDeepEqual(new MyMap([['a', 1]]), new MyMap([['a', 2]]))).toBe(false);
419
- });