@dungarees/core 0.11.0 → 0.11.2
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/application.d.ts +27 -21
- package/application.js +14 -15
- package/error.d.ts +6 -0
- package/error.js +14 -0
- package/error.test.d.ts +1 -0
- package/error.test.js +44 -0
- package/event.d.ts +12 -0
- package/event.js +8 -0
- package/event.test.d.ts +1 -0
- package/event.test.js +22 -0
- package/fake.d.ts +5 -5
- package/fake.js +5 -10
- package/fake.test.js +8 -0
- package/marbles-vitest.d.ts +18 -14
- package/marbles-vitest.js +57 -52
- package/marbles-vitest.test.js +26 -14
- package/marbles.d.ts +5 -4
- package/marbles.js +39 -36
- package/package.json +28 -2
- package/tsconfig.base.json +35 -0
- package/type-util.d.ts +17 -9
- package/type-util.test.js +71 -59
- package/util.d.ts +30 -12
- package/util.js +102 -82
- package/util.test.js +239 -22
package/marbles.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DetachableMethods } from './type-util.ts';
|
|
1
2
|
import type { Observable } from 'rxjs';
|
|
2
3
|
import { Expect } from 'rxjs-marbles/expect.js';
|
|
3
4
|
import { marbles } from 'rxjs-marbles/jest/index.js';
|
|
@@ -5,13 +6,13 @@ import type { ExpectHelpers, TestObservableLike } from 'rxjs-marbles/types.js';
|
|
|
5
6
|
type Marbles = typeof marbles;
|
|
6
7
|
type MarblesRunner = Parameters<Marbles>[0];
|
|
7
8
|
type MarblesParam = Parameters<MarblesRunner>[0];
|
|
8
|
-
type Runner = (m: MarblesExtensions, ...args:
|
|
9
|
+
type Runner<ARGS extends unknown[] = []> = (m: MarblesExtensions, ...args: ARGS) => void | Promise<void>;
|
|
9
10
|
type MarbleFunctions = Record<string, () => void>;
|
|
10
11
|
type MarblesExtensions = {
|
|
11
12
|
coldCall: (marble: string, functions: MarbleFunctions) => void;
|
|
12
13
|
coldBoolean: (marble: string) => TestObservableLike<boolean>;
|
|
13
|
-
expect: <T =
|
|
14
|
-
} & MarblesParam
|
|
14
|
+
expect: <T = unknown>(actual: Observable<T>, subscription?: string) => ExtendedExpect<T>;
|
|
15
|
+
} & DetachableMethods<MarblesParam>;
|
|
15
16
|
declare class ExtendedExpect<T> extends Expect<T> {
|
|
16
17
|
readonly actual_: Observable<T>;
|
|
17
18
|
readonly helpers_: ExpectHelpers;
|
|
@@ -19,7 +20,7 @@ declare class ExtendedExpect<T> extends Expect<T> {
|
|
|
19
20
|
constructor(actual_: Observable<T>, helpers_: ExpectHelpers, subscription_?: string);
|
|
20
21
|
toBeObservableBoolean(marble: string): void;
|
|
21
22
|
}
|
|
22
|
-
export declare const coreMarbles: (runner: Runner) => (() => void);
|
|
23
|
+
export declare const coreMarbles: <ARGS extends unknown[] = []>(runner: Runner<ARGS>) => ((...args: ARGS) => void | Promise<void>);
|
|
23
24
|
export declare const MARBLES_BOOLEAN: {
|
|
24
25
|
t: boolean;
|
|
25
26
|
f: boolean;
|
package/marbles.js
CHANGED
|
@@ -11,42 +11,45 @@ class ExtendedExpect extends Expect {
|
|
|
11
11
|
this.toBeObservable(marble, MARBLES_BOOLEAN);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
-
export const coreMarbles = (runner) => (...args) =>
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
})
|
|
14
|
+
export const coreMarbles = (runner) => (...args) => {
|
|
15
|
+
const runInMarbles = marbles((m) => {
|
|
16
|
+
const coldCall = (marble, functions) => {
|
|
17
|
+
const marbleDefinition = Object.fromEntries(Object.keys(functions).map((key) => [key, key]));
|
|
18
|
+
m.cold(marble, marbleDefinition).subscribe((key) => {
|
|
19
|
+
functions[key]?.();
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
const coldBoolean = (marble) => m.cold(marble, MARBLES_BOOLEAN);
|
|
23
|
+
// This function and the ExtendedExpect depends on internals of the `rxjs-marbles` library
|
|
24
|
+
// potentially not future proof
|
|
25
|
+
const expect = (actual, subscription) => {
|
|
26
|
+
const { helpers_ } = m;
|
|
27
|
+
return new ExtendedExpect(actual, helpers_, subscription);
|
|
28
|
+
};
|
|
29
|
+
// The methods on `m` (the RunContext) are on the prototype, so we have to bind the original
|
|
30
|
+
// ones to be able to use destructuring
|
|
31
|
+
return runner({
|
|
32
|
+
get autoFlush() {
|
|
33
|
+
return m.autoFlush;
|
|
34
|
+
},
|
|
35
|
+
coldCall,
|
|
36
|
+
coldBoolean,
|
|
37
|
+
expect,
|
|
38
|
+
equal: m.equal.bind(m),
|
|
39
|
+
cold: m.cold.bind(m),
|
|
40
|
+
bind: m.bind.bind(m),
|
|
41
|
+
configure: m.configure.bind(m),
|
|
42
|
+
flush: m.flush.bind(m),
|
|
43
|
+
has: m.has.bind(m),
|
|
44
|
+
hot: m.hot.bind(m),
|
|
45
|
+
reframe: m.reframe.bind(m),
|
|
46
|
+
scheduler: m.scheduler,
|
|
47
|
+
teardown: m.teardown.bind(m),
|
|
48
|
+
time: m.time.bind(m),
|
|
49
|
+
}, ...args);
|
|
50
|
+
});
|
|
51
|
+
return runInMarbles();
|
|
52
|
+
};
|
|
50
53
|
export const MARBLES_BOOLEAN = {
|
|
51
54
|
t: true,
|
|
52
55
|
f: false,
|
package/package.json
CHANGED
|
@@ -14,13 +14,38 @@
|
|
|
14
14
|
"vitest": "^3.0.2"
|
|
15
15
|
},
|
|
16
16
|
"author": "info@productkind.com",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/productkind/monorepo.git",
|
|
20
|
+
"directory": "dungarees/src/core"
|
|
21
|
+
},
|
|
17
22
|
"license": "MIT",
|
|
18
|
-
"
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"hotscript": "^1.0.13",
|
|
25
|
+
"rxjs": "^7.8.1"
|
|
26
|
+
},
|
|
27
|
+
"version": "0.11.2",
|
|
19
28
|
"exports": {
|
|
20
29
|
"./application.ts": {
|
|
21
30
|
"import": "./application.js",
|
|
22
31
|
"types": "./application.d.ts"
|
|
23
32
|
},
|
|
33
|
+
"./error.test.ts": {
|
|
34
|
+
"import": "./error.test.js",
|
|
35
|
+
"types": "./error.test.d.ts"
|
|
36
|
+
},
|
|
37
|
+
"./error.ts": {
|
|
38
|
+
"import": "./error.js",
|
|
39
|
+
"types": "./error.d.ts"
|
|
40
|
+
},
|
|
41
|
+
"./event.test.ts": {
|
|
42
|
+
"import": "./event.test.js",
|
|
43
|
+
"types": "./event.test.d.ts"
|
|
44
|
+
},
|
|
45
|
+
"./event.ts": {
|
|
46
|
+
"import": "./event.js",
|
|
47
|
+
"types": "./event.d.ts"
|
|
48
|
+
},
|
|
24
49
|
"./fake.test.ts": {
|
|
25
50
|
"import": "./fake.test.js",
|
|
26
51
|
"types": "./fake.test.d.ts"
|
|
@@ -476,6 +501,7 @@
|
|
|
476
501
|
"./util.ts": {
|
|
477
502
|
"import": "./util.js",
|
|
478
503
|
"types": "./util.d.ts"
|
|
479
|
-
}
|
|
504
|
+
},
|
|
505
|
+
"./tsconfig.base.json": "./tsconfig.base.json"
|
|
480
506
|
}
|
|
481
507
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "esnext",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext", "webworker"],
|
|
5
|
+
"types": ["node", "vite/client"],
|
|
6
|
+
"allowJs": true,
|
|
7
|
+
"allowImportingTsExtensions": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"allowSyntheticDefaultImports": true,
|
|
12
|
+
"exactOptionalPropertyTypes": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"noImplicitAny": true,
|
|
15
|
+
"noImplicitOverride": true,
|
|
16
|
+
"noImplicitReturns": true,
|
|
17
|
+
"noImplicitThis": true,
|
|
18
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
19
|
+
"noUncheckedIndexedAccess": true,
|
|
20
|
+
"noUnusedLocals": true,
|
|
21
|
+
"noUnusedParameters": true,
|
|
22
|
+
"strictBindCallApply": true,
|
|
23
|
+
"strictFunctionTypes": true,
|
|
24
|
+
"strictNullChecks": true,
|
|
25
|
+
"strictPropertyInitialization": true,
|
|
26
|
+
"useUnknownInCatchVariables": true,
|
|
27
|
+
"noFallthroughCasesInSwitch": true,
|
|
28
|
+
"module": "nodenext",
|
|
29
|
+
"moduleResolution": "nodenext",
|
|
30
|
+
"resolveJsonModule": true,
|
|
31
|
+
"isolatedModules": true,
|
|
32
|
+
"jsx": "react-jsx",
|
|
33
|
+
"sourceMap": true
|
|
34
|
+
}
|
|
35
|
+
}
|
package/type-util.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Fn } from 'hotscript';
|
|
1
2
|
export type StringLiteral<T> = T extends string ? (string extends T ? never : T) : never;
|
|
2
3
|
export type ObjectWithStringLiteralKey<KEY, VALUE> = {
|
|
3
4
|
[K in StringLiteral<KEY>]: VALUE;
|
|
@@ -6,28 +7,26 @@ export type JsonType = number | string | boolean | null | undefined | JsonType[]
|
|
|
6
7
|
export type JsonObject = {
|
|
7
8
|
[key: string]: JsonType;
|
|
8
9
|
};
|
|
10
|
+
export type Serializable = JsonType;
|
|
9
11
|
export type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array;
|
|
10
12
|
export type TokenNonEmptyString<TOKEN extends string | number> = TOKEN extends '' ? never : TOKEN;
|
|
11
|
-
export type Guard<T =
|
|
13
|
+
export type Guard<T = unknown> = (arg: unknown) => arg is T;
|
|
12
14
|
export type GetGuarded<GUARD extends Guard> = GUARD extends (arg: unknown) => arg is infer GUARDED ? GUARDED : never;
|
|
13
|
-
export type EntryTuple<KEY extends string = string, VALUE =
|
|
14
|
-
export type RecordToEntries<RECORD extends Record<string,
|
|
15
|
+
export type EntryTuple<KEY extends string = string, VALUE = unknown> = [KEY, VALUE];
|
|
16
|
+
export type RecordToEntries<RECORD extends Record<string, unknown>, KEY = keyof RECORD> = KEY extends string ? (KEY extends keyof RECORD ? EntryTuple<KEY, RECORD[KEY]> : never) : never;
|
|
15
17
|
export type GetValueByKey<ENTRIES extends EntryTuple, KEY extends string> = ENTRIES extends EntryTuple<KEY, infer ENTRY> ? ENTRY : never;
|
|
16
18
|
export type GetKey<ENTRIES extends EntryTuple> = ENTRIES[0];
|
|
17
19
|
export type GetValue<ENTRIES extends EntryTuple> = ENTRIES[1];
|
|
18
|
-
export type
|
|
20
|
+
export type FilterRecord<RECORD extends Record<string | number | symbol, unknown>, TYPE> = Pick<RECORD, {
|
|
19
21
|
[K in keyof RECORD]: RECORD[K] extends TYPE ? K : never;
|
|
20
22
|
}[keyof RECORD]>;
|
|
21
|
-
export type FilterRecord<RECORD extends Record<string | number | symbol, any>, TYPE> = {
|
|
22
|
-
[K in keyof RECORD]: RECORD[K] extends TYPE ? RECORD[K] : never;
|
|
23
|
-
};
|
|
24
23
|
export type Split<STRING extends string, DELIMITER extends string> = SplitHelper<STRING, DELIMITER>;
|
|
25
24
|
type SplitHelper<STRING extends string, DELIMITER extends string, ACC extends readonly string[] = []> = STRING extends `${infer FIRST}${DELIMITER}${infer REST}` ? SplitHelper<REST, DELIMITER, [...ACC, FIRST]> : readonly [...ACC, STRING];
|
|
26
25
|
export type SplitObjectPath<PATH extends string> = Split<PATH, '.'>;
|
|
27
26
|
export type SplitFilePath<PATH extends string> = Split<PATH, '/'>;
|
|
28
27
|
export type GetAllPaths<OBJECT, PATH extends string = ''> = PathsHelper<OBJECT, PATH, never>;
|
|
29
28
|
type PathsHelper<OBJECT, PATH extends string, ACC extends string> = {
|
|
30
|
-
[K in keyof OBJECT & string]: PATH extends '' ? K | (OBJECT[K] extends Record<string,
|
|
29
|
+
[K in keyof OBJECT & string]: PATH extends '' ? K | (OBJECT[K] extends Record<string, unknown> ? PathsHelper<OBJECT[K], K, K> : never) : `${PATH}.${K}` | (OBJECT[K] extends Record<string, unknown> ? PathsHelper<OBJECT[K], `${PATH}.${K}`, `${PATH}.${K}` | ACC> : never);
|
|
31
30
|
}[keyof OBJECT & string] | ACC;
|
|
32
31
|
export type GetValueByPath<OBJECT, PATH extends string> = PATH extends keyof OBJECT ? OBJECT[PATH] : PATH extends `${infer K}.${infer Rest}` ? K extends keyof OBJECT ? GetValueByPath<OBJECT[K], Rest & string> : never : never;
|
|
33
32
|
export type JoinArray<STRINGS extends readonly string[], DELIMITER extends string, ACC extends string = ''> = STRINGS extends [] ? '' : STRINGS extends [infer L, ...infer R] ? L extends string ? R['length'] extends 0 ? `${ACC}${L & string}` : R extends string[] ? JoinArray<R, DELIMITER, `${ACC}${L}${DELIMITER}`> : never : ACC : never;
|
|
@@ -43,8 +42,17 @@ export type Mutable<T> = {
|
|
|
43
42
|
-readonly [K in keyof T]: T[K];
|
|
44
43
|
};
|
|
45
44
|
export type PartialBesides<OBJECT, KEYS extends keyof OBJECT> = Partial<Omit<OBJECT, KEYS>> & Pick<OBJECT, KEYS>;
|
|
45
|
+
export type FlattenIntersection<OBJECT> = {
|
|
46
|
+
[KEY in keyof OBJECT]: OBJECT[KEY];
|
|
47
|
+
};
|
|
48
|
+
export type DetachableMethods<OBJECT> = {
|
|
49
|
+
[KEY in keyof OBJECT]: OmitThisParameter<OBJECT[KEY]>;
|
|
50
|
+
};
|
|
46
51
|
export type DeepPartial<T> = {
|
|
47
52
|
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
|
|
48
53
|
};
|
|
49
|
-
export type SyncFunctionToAsync<FUNC extends (...args:
|
|
54
|
+
export type SyncFunctionToAsync<FUNC extends (...args: never[]) => unknown> = FUNC extends (...args: infer ARGS) => infer RETURN ? (...args: ARGS) => Promise<RETURN> : never;
|
|
55
|
+
export interface StaticFn<RETURN> extends Fn {
|
|
56
|
+
return: RETURN;
|
|
57
|
+
}
|
|
50
58
|
export {};
|
package/type-util.test.js
CHANGED
|
@@ -1,41 +1,38 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { test } from 'vitest';
|
|
1
|
+
import { expect, expectTypeOf, test } from 'vitest';
|
|
3
2
|
test('Split<PATH, DELIMITER>', () => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
assert();
|
|
8
|
-
assert();
|
|
3
|
+
expectTypeOf().toEqualTypeOf();
|
|
4
|
+
expectTypeOf().toEqualTypeOf();
|
|
5
|
+
expectTypeOf().toEqualTypeOf();
|
|
9
6
|
});
|
|
10
7
|
test('SplitObjectPath<PATH>', () => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
assert();
|
|
8
|
+
expectTypeOf().toEqualTypeOf();
|
|
9
|
+
expectTypeOf().toEqualTypeOf();
|
|
10
|
+
expectTypeOf().toEqualTypeOf();
|
|
15
11
|
});
|
|
16
12
|
test('SplitFilePath<PATH>', () => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
assert();
|
|
13
|
+
expectTypeOf().toEqualTypeOf();
|
|
14
|
+
expectTypeOf().toEqualTypeOf();
|
|
15
|
+
expectTypeOf().toEqualTypeOf();
|
|
21
16
|
});
|
|
22
17
|
test('StringLiteral<LITERAL>', () => {
|
|
23
18
|
const literal = 'asd';
|
|
24
|
-
|
|
19
|
+
expectTypeOf(literal).toEqualTypeOf();
|
|
20
|
+
// Widened through an annotation rather than an `as` cast, so rule 4 still holds.
|
|
21
|
+
const widened = 'asd';
|
|
25
22
|
// @ts-expect-error it has to be a literal
|
|
26
|
-
const nonLiteral =
|
|
27
|
-
|
|
23
|
+
const nonLiteral = widened;
|
|
24
|
+
expectTypeOf(nonLiteral).toEqualTypeOf();
|
|
28
25
|
});
|
|
29
26
|
test('ObjectWithStringLiteralKey<KEY, VALUE>', () => {
|
|
30
27
|
const obj = {
|
|
31
28
|
a: 1,
|
|
32
29
|
};
|
|
33
|
-
|
|
30
|
+
expectTypeOf(obj).toEqualTypeOf();
|
|
34
31
|
// @ts-expect-error it has to be a literal
|
|
35
32
|
const nonLiteral = {
|
|
36
33
|
a: 1,
|
|
37
34
|
};
|
|
38
|
-
|
|
35
|
+
expectTypeOf(nonLiteral).toEqualTypeOf();
|
|
39
36
|
});
|
|
40
37
|
test('JsonType', () => {
|
|
41
38
|
const json = {
|
|
@@ -45,91 +42,106 @@ test('JsonType', () => {
|
|
|
45
42
|
d: null,
|
|
46
43
|
e: [1, '2', true, null, [1, '2', true, null]],
|
|
47
44
|
};
|
|
48
|
-
|
|
45
|
+
expect(json).toBeDefined();
|
|
49
46
|
// @ts-expect-error it cannot be a function
|
|
50
47
|
const nonJson = {
|
|
51
48
|
f: () => { },
|
|
52
49
|
};
|
|
53
|
-
|
|
50
|
+
expect(nonJson).toBeDefined();
|
|
54
51
|
});
|
|
55
52
|
test('TokenNonEmptyString<TOKEN>', () => {
|
|
56
53
|
const token = 'a';
|
|
57
|
-
|
|
54
|
+
expectTypeOf(token).toEqualTypeOf();
|
|
58
55
|
// @ts-expect-error it cannot be empty
|
|
59
56
|
const nonToken = '';
|
|
60
|
-
|
|
57
|
+
expectTypeOf(nonToken).toEqualTypeOf();
|
|
61
58
|
});
|
|
62
59
|
test('Guard<TYPE>', () => {
|
|
63
60
|
const guard = (arg) => arg === 1;
|
|
64
|
-
|
|
61
|
+
expectTypeOf(guard).toEqualTypeOf();
|
|
65
62
|
// @ts-expect-error it has to be a guard
|
|
66
63
|
const nonGuard = (arg) => arg === 1;
|
|
67
|
-
|
|
64
|
+
expectTypeOf(nonGuard).toEqualTypeOf();
|
|
68
65
|
});
|
|
69
66
|
test('GetGuarded<GUARD>', () => {
|
|
70
|
-
const
|
|
71
|
-
|
|
67
|
+
const testUnused_guard = (arg) => arg === 1;
|
|
68
|
+
expectTypeOf().toEqualTypeOf();
|
|
72
69
|
});
|
|
73
70
|
test('EntryTuples', () => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
expectTypeOf().toEqualTypeOf();
|
|
72
|
+
expectTypeOf().toEqualTypeOf();
|
|
73
|
+
expectTypeOf().toEqualTypeOf();
|
|
74
|
+
expectTypeOf().toEqualTypeOf();
|
|
78
75
|
});
|
|
79
76
|
test('FilterRecord<RECORD, TYPE>', () => {
|
|
80
|
-
|
|
81
|
-
assert();
|
|
77
|
+
expectTypeOf().toEqualTypeOf();
|
|
82
78
|
});
|
|
83
79
|
test('GetAllPaths<OBJECT>', () => {
|
|
84
|
-
|
|
80
|
+
expectTypeOf().toEqualTypeOf();
|
|
85
81
|
});
|
|
86
82
|
test('GetValuesByPath<OBJECT, PATH>', () => {
|
|
87
|
-
|
|
83
|
+
expectTypeOf().toEqualTypeOf();
|
|
88
84
|
});
|
|
89
85
|
test('JoinArray<STRINGS, DELIMITER>', () => {
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
expectTypeOf().toEqualTypeOf();
|
|
87
|
+
expectTypeOf().toEqualTypeOf();
|
|
92
88
|
});
|
|
93
89
|
test('FromCamelCase<STRING>', () => {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
expectTypeOf().toEqualTypeOf();
|
|
91
|
+
expectTypeOf().toEqualTypeOf();
|
|
92
|
+
expectTypeOf().toEqualTypeOf();
|
|
97
93
|
});
|
|
98
94
|
test('ToCamelCase<STRING[]>', () => {
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
expectTypeOf().toEqualTypeOf();
|
|
96
|
+
expectTypeOf().toEqualTypeOf();
|
|
101
97
|
});
|
|
102
98
|
test('FromKebabCase<STRING>', () => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
99
|
+
expectTypeOf().toEqualTypeOf();
|
|
100
|
+
expectTypeOf().toEqualTypeOf();
|
|
101
|
+
expectTypeOf().toEqualTypeOf();
|
|
106
102
|
});
|
|
107
103
|
test('ToKebabCase<STRING[]>', () => {
|
|
108
|
-
|
|
109
|
-
|
|
104
|
+
expectTypeOf().toEqualTypeOf();
|
|
105
|
+
expectTypeOf().toEqualTypeOf();
|
|
110
106
|
});
|
|
111
107
|
test('FromSnakeCase<STRING>', () => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
108
|
+
expectTypeOf().toEqualTypeOf();
|
|
109
|
+
expectTypeOf().toEqualTypeOf();
|
|
110
|
+
expectTypeOf().toEqualTypeOf();
|
|
115
111
|
});
|
|
116
112
|
test('ToSnakeCase<STRING[]>', () => {
|
|
117
|
-
|
|
118
|
-
|
|
113
|
+
expectTypeOf().toEqualTypeOf();
|
|
114
|
+
expectTypeOf().toEqualTypeOf();
|
|
119
115
|
});
|
|
120
116
|
test('Mutable<TYPE>', () => {
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
expectTypeOf().toEqualTypeOf();
|
|
118
|
+
expectTypeOf().toEqualTypeOf();
|
|
119
|
+
});
|
|
120
|
+
test('FlattenIntersection<OBJECT>', () => {
|
|
121
|
+
expectTypeOf().toEqualTypeOf();
|
|
122
|
+
expectTypeOf().toEqualTypeOf();
|
|
123
123
|
});
|
|
124
124
|
test('PartialBesides<OBJECT, KEYS>', () => {
|
|
125
|
-
|
|
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();
|
|
126
128
|
});
|
|
127
129
|
test('DeepPartial<T> - single level', () => {
|
|
128
|
-
|
|
130
|
+
expectTypeOf().toEqualTypeOf();
|
|
129
131
|
});
|
|
130
132
|
test('DeepPartial<T> - nested props', () => {
|
|
131
|
-
|
|
133
|
+
expectTypeOf().toEqualTypeOf();
|
|
132
134
|
});
|
|
133
135
|
test('SyncFunctionToAsync<FUNC>', () => {
|
|
134
|
-
|
|
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();
|
|
135
147
|
});
|
package/util.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Guard, JsonType } from './type-util.ts';
|
|
2
|
-
import type { Call, Fn } from 'hotscript';
|
|
1
|
+
import type { FromCamelCase, FromKebabCase, Guard, JoinArray, JsonType, ObjectWithStringLiteralKey, Split, StringLiteral, ToCamelCase, ToKebabCase } from './type-util.ts';
|
|
2
|
+
import type { Call, Fn, Objects, Pipe } from 'hotscript';
|
|
3
3
|
export declare const typeKey: unique symbol;
|
|
4
4
|
export declare const makeObjectFromStringLiteral: <KEY, VALUE>(key: StringLiteral<KEY>, value: VALUE) => ObjectWithStringLiteralKey<KEY, VALUE>;
|
|
5
5
|
export declare const split: <const STRING extends string, const DELIMITER extends string>(str: STRING, delimiter: DELIMITER) => Split<STRING, DELIMITER>;
|
|
@@ -9,20 +9,20 @@ export declare const pluralize: (str: string, value: number, prefix?: boolean) =
|
|
|
9
9
|
export declare const toCamelCase: <const SEGMENTS extends readonly string[]>(segments: SEGMENTS) => ToCamelCase<SEGMENTS>;
|
|
10
10
|
export declare const kebabCase2camelCase: <const KEBAB_CASE extends string>(kebabCase: KEBAB_CASE) => ToCamelCase<FromKebabCase<KEBAB_CASE>>;
|
|
11
11
|
export declare const camelCase2kebabCase: <const CAMEL_CASE extends string>(camelCase: CAMEL_CASE) => ToKebabCase<FromCamelCase<CAMEL_CASE>>;
|
|
12
|
-
export declare const isDeepEqual: (a:
|
|
13
|
-
export declare const deepEqualPartial: (actual:
|
|
12
|
+
export declare const isDeepEqual: (a: unknown, b: unknown) => boolean;
|
|
13
|
+
export declare const deepEqualPartial: (actual: unknown, expected: unknown) => boolean;
|
|
14
14
|
export declare const findByPattern: <MATCH extends JsonType, const PATTERNS extends readonly FindByPatterns[]>(patterns: PATTERNS, itemToMatch: MATCH) => GetValueFromPatternList<PATTERNS> | undefined;
|
|
15
15
|
export declare const optionalPatternToList: <const VALUE>(value: VALUE) => OptionalPatternToList<VALUE>;
|
|
16
16
|
export type FindByPatterns = FindByPattern | FindByPartialPattern | FindByDefault;
|
|
17
|
-
export type FindByPattern<VALUE =
|
|
17
|
+
export type FindByPattern<VALUE = unknown, PATTERN extends JsonType = JsonType> = {
|
|
18
18
|
readonly value: VALUE;
|
|
19
19
|
readonly pattern: PATTERN;
|
|
20
20
|
};
|
|
21
|
-
export type FindByPartialPattern<VALUE =
|
|
21
|
+
export type FindByPartialPattern<VALUE = unknown, PATTERN extends JsonType = JsonType> = {
|
|
22
22
|
readonly value: VALUE;
|
|
23
23
|
readonly patternPartial: Partial<PATTERN>;
|
|
24
24
|
};
|
|
25
|
-
export type FindByDefault<VALUE =
|
|
25
|
+
export type FindByDefault<VALUE = unknown> = {
|
|
26
26
|
readonly value: VALUE;
|
|
27
27
|
};
|
|
28
28
|
export type OptionalPatternList<VALUE, PATTERN extends JsonType> = VALUE | Array<FindByPattern<VALUE, PATTERN> | FindByPartialPattern<VALUE, PATTERN> | FindByDefault<VALUE>>;
|
|
@@ -36,7 +36,7 @@ type AssertPredicateArg<T> = {
|
|
|
36
36
|
predicate: (value: T) => boolean;
|
|
37
37
|
message: ErrorMessage<T>;
|
|
38
38
|
};
|
|
39
|
-
export declare const assertPredicate: <T>({ value, predicate, message
|
|
39
|
+
export declare const assertPredicate: <T>({ value, predicate, message }: AssertPredicateArg<T>) => T;
|
|
40
40
|
export declare const assertImpossible: (message: string) => never;
|
|
41
41
|
type ErrorMessage<T> = string | ((value: T) => string);
|
|
42
42
|
type AssertTypeByGuardArg<T, V> = {
|
|
@@ -44,10 +44,28 @@ type AssertTypeByGuardArg<T, V> = {
|
|
|
44
44
|
guard: Guard<T>;
|
|
45
45
|
message: ErrorMessage<V>;
|
|
46
46
|
};
|
|
47
|
-
export declare const unPrototypeProperties: <const T extends
|
|
48
|
-
|
|
47
|
+
export declare const unPrototypeProperties: <const T extends object, const KEYS extends keyof T>(obj: T, keys: KEYS[]) => Pick<T, KEYS>;
|
|
48
|
+
export declare const boolFromThrow: (fn: () => void) => boolean;
|
|
49
|
+
export declare const boolFromThrowAsync: (fn: () => Promise<void>) => Promise<boolean>;
|
|
50
|
+
type MapConstResult<ARRAY extends readonly unknown[], F extends Fn> = {
|
|
49
51
|
readonly [K in keyof ARRAY]: Call<F, ARRAY[K]>;
|
|
50
52
|
};
|
|
51
|
-
export declare
|
|
52
|
-
export declare
|
|
53
|
+
export declare function mapConst<const ARRAY extends readonly unknown[]>(array: ARRAY): <F extends Fn>(transformer: (value: ARRAY[number], index: Pipe<ARRAY, [Objects.Keys]>) => MapConstResult<ARRAY, F>[number]) => MapConstResult<ARRAY, F>;
|
|
54
|
+
export declare function mapConst<const ARRAY extends readonly unknown[], const R>(array: ARRAY, transformer: (value: ARRAY[number], index: Pipe<ARRAY, [Objects.Keys]>) => R): {
|
|
55
|
+
readonly [K in keyof ARRAY]: R;
|
|
56
|
+
};
|
|
57
|
+
type MapConstKeysToEntriesResult<ARRAY extends readonly unknown[], F extends Fn> = {
|
|
58
|
+
readonly [K in keyof ARRAY]: [ARRAY[K], Call<F, ARRAY[K]>];
|
|
59
|
+
};
|
|
60
|
+
export declare function mapConstKeysToEntries<const ARRAY extends readonly unknown[]>(array: ARRAY): <F extends Fn>(transformer: (value: ARRAY[number], index: Pipe<ARRAY, [Objects.Keys]>) => MapConstKeysToEntriesResult<ARRAY, F>[number][1]) => MapConstKeysToEntriesResult<ARRAY, F>;
|
|
61
|
+
export declare function mapConstKeysToEntries<const ARRAY extends readonly unknown[], const R>(array: ARRAY, transformer: (value: ARRAY[number], index: Pipe<ARRAY, [Objects.Keys]>) => R): {
|
|
62
|
+
readonly [K in keyof ARRAY]: [ARRAY[K], R];
|
|
63
|
+
};
|
|
64
|
+
export declare const objectFromConstEntries: <const ENTRIES extends readonly (readonly [string, unknown])[]>(entries: ENTRIES) => { [K in ENTRIES[number] as K[0]]: K[1]; };
|
|
65
|
+
export declare function mapObjectFromKeys<const KEYS extends readonly string[]>(keys: KEYS): <F extends Fn>(transformer: (key: KEYS[number], index: Pipe<KEYS, [Objects.Keys]>) => Call<F, KEYS[number]>) => {
|
|
66
|
+
[K in MapConstKeysToEntriesResult<KEYS, F>[number] as K[0]]: K[1];
|
|
67
|
+
};
|
|
68
|
+
export declare function mapObjectFromKeys<const KEYS extends readonly string[], const R>(keys: KEYS, transformer: (key: KEYS[number], index: Pipe<KEYS, [Objects.Keys]>) => R): {
|
|
69
|
+
[K in KEYS[number]]: R;
|
|
70
|
+
};
|
|
53
71
|
export {};
|