Skip to content

Commit a4342bf

Browse files
refactor Arguments.ts
1 parent 53e0683 commit a4342bf

File tree

1 file changed

+81
-88
lines changed

1 file changed

+81
-88
lines changed

src/Arguments.ts

Lines changed: 81 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,98 @@
11
type PredicateFunction<T> = (arg: T) => boolean
22
type ArgumentOptions = {
3-
inverseMatch?: boolean
3+
inverseMatch?: boolean
44
}
55
class BaseArgument<T> {
6-
constructor(
7-
private _description: string,
8-
private _matchingFunction: PredicateFunction<T>,
9-
private _options?: ArgumentOptions
10-
) { }
11-
12-
matches(arg: T) {
13-
const inverseMatch = this._options?.inverseMatch ?? false
14-
return inverseMatch ? !this._matchingFunction(arg) : this._matchingFunction(arg);
15-
}
16-
17-
toString() {
18-
return this._description;
19-
}
20-
21-
[Symbol.for('nodejs.util.inspect.custom')]() {
22-
return this._description;
23-
}
6+
constructor(
7+
private _description: string,
8+
private _matchingFunction: PredicateFunction<T>,
9+
private _options?: ArgumentOptions
10+
) { }
11+
12+
matches(arg: T) {
13+
const inverseMatch = this._options?.inverseMatch ?? false
14+
return inverseMatch ? !this._matchingFunction(arg) : this._matchingFunction(arg)
15+
}
16+
17+
toString() {
18+
return this._description
19+
}
20+
21+
[Symbol.for('nodejs.util.inspect.custom')]() {
22+
return this._description
23+
}
2424
}
2525

2626
export class Argument<T> extends BaseArgument<T> {
27-
private readonly _type = 'SingleArgument';
28-
constructor(description: string, matchingFunction: PredicateFunction<T>, options?: ArgumentOptions) {
29-
super(description, matchingFunction, options);
30-
}
31-
get type(): 'SingleArgument' {
32-
return this._type;
33-
}
27+
private readonly _type = 'SingleArgument';
28+
get type(): 'SingleArgument' {
29+
return this._type
30+
}
3431
}
3532

3633
export class AllArguments<T extends any[]> extends BaseArgument<T> {
37-
private readonly _type = 'AllArguments';
38-
constructor() {
39-
super('{all}', () => true, {});
40-
}
41-
get type(): 'AllArguments' {
42-
return this._type;
43-
}
34+
private readonly _type = 'AllArguments';
35+
constructor() {
36+
super('{all}', () => true, {})
37+
}
38+
get type(): 'AllArguments' {
39+
return this._type // TODO: Needed?
40+
}
4441
}
4542

4643
export namespace Arg {
47-
type ExtractFirstArg<T> = T extends AllArguments<infer TArgs> ? TArgs[0] : T
48-
type ReturnArg<T> = Argument<T> & T;
49-
type Inversable<T> = T & { not: T }
50-
const factory = (factoryF: Function) => <T>(...args: any[]): T => factoryF(...args)
51-
const toStringify = (obj: any) => {
52-
if (typeof obj.inspect === 'function')
53-
return obj.inspect();
54-
55-
if (typeof obj.toString === 'function')
56-
return obj.toString();
57-
58-
return obj;
44+
type Inversable<T> = T & { not: T }
45+
type ExtractFirstArg<T> = T extends AllArguments<infer TArgs> ? TArgs[0] : T
46+
type ReturnArg<T> = Argument<T> & T
47+
const createInversable = <TArg, TReturn>(target: (arg: TArg, opt?: ArgumentOptions) => TReturn): Inversable<(arg: TArg) => TReturn> => {
48+
const inversable = (arg: TArg) => target(arg)
49+
inversable.not = (arg: TArg) => target(arg, { inverseMatch: true })
50+
return inversable
51+
}
52+
53+
const toStringify = (obj: any) => {
54+
if (typeof obj.inspect === 'function') return obj.inspect()
55+
if (typeof obj.toString === 'function') return obj.toString()
56+
return obj
57+
}
58+
59+
export const all = <T extends any[]>(): AllArguments<T> => new AllArguments<T>()
60+
61+
type Is = <T>(predicate: PredicateFunction<ExtractFirstArg<T>>) => ReturnArg<ExtractFirstArg<T>>
62+
const isFunction = <T>(predicate: PredicateFunction<ExtractFirstArg<T>>, options?: ArgumentOptions) => new Argument(
63+
`{predicate ${toStringify(predicate)}}`, predicate, options
64+
)
65+
export const is = createInversable(isFunction) as Inversable<Is>
66+
67+
type MapAnyReturn<T> = T extends 'any' ?
68+
ReturnArg<any> : T extends 'string' ?
69+
ReturnArg<string> : T extends 'number' ?
70+
ReturnArg<number> : T extends 'boolean' ?
71+
ReturnArg<boolean> : T extends 'symbol' ?
72+
ReturnArg<symbol> : T extends 'undefined' ?
73+
ReturnArg<undefined> : T extends 'object' ?
74+
ReturnArg<object> : T extends 'function' ?
75+
ReturnArg<Function> : T extends 'array' ?
76+
ReturnArg<any[]> : any
77+
78+
type AnyType = 'string' | 'number' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | 'array' | 'any'
79+
type Any = <T extends AnyType = 'any'>(type?: T) => MapAnyReturn<T>
80+
81+
const anyFunction = (type: AnyType = 'any', options?: ArgumentOptions) => {
82+
const description = `{type ${type}}`
83+
const predicate = (x: any) => {
84+
switch (type) {
85+
case 'any':
86+
return true
87+
case 'array':
88+
return Array.isArray(x)
89+
default:
90+
return typeof x === type
91+
}
5992
}
6093

61-
export const all = <T extends any[]>(): AllArguments<T> => new AllArguments<T>();
62-
63-
type Is = <T>(predicate: PredicateFunction<ExtractFirstArg<T>>) => ReturnArg<ExtractFirstArg<T>>
64-
const isFunction = <T extends PredicateFunction<T>>(predicate: T, options?: ArgumentOptions) => new Argument(
65-
`{predicate ${toStringify(predicate)}}`, predicate, options
66-
);
67-
68-
const isArgFunction: Inversable<Is> = (predicate) => factory(isFunction)(predicate);
69-
isArgFunction.not = (predicate) => factory(isFunction)(predicate, { inverseMatch: true });
70-
export const is = isArgFunction
71-
72-
type MapAnyReturn<T> = T extends 'any' ?
73-
ReturnArg<any> : T extends 'string' ?
74-
ReturnArg<string> : T extends 'number' ?
75-
ReturnArg<number> : T extends 'boolean' ?
76-
ReturnArg<boolean> : T extends 'symbol' ?
77-
ReturnArg<symbol> : T extends 'undefined' ?
78-
ReturnArg<undefined> : T extends 'object' ?
79-
ReturnArg<object> : T extends 'function' ?
80-
ReturnArg<Function> : T extends 'array' ?
81-
ReturnArg<any[]> : any;
82-
83-
type AnyType = 'string' | 'number' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | 'array' | 'any';
84-
type Any = <T extends AnyType = 'any'>(type?: T) => MapAnyReturn<T>;
85-
86-
const anyFunction = (type: AnyType = 'any', options?: ArgumentOptions) => {
87-
const description = !type ? '{any arg}' : `{type ${type}}`;
88-
const predicate = (x: any) => {
89-
switch (type) {
90-
case 'any':
91-
return true;
92-
case 'array':
93-
return Array.isArray(x);
94-
default:
95-
return typeof x === type;
96-
}
97-
}
98-
99-
return new Argument(description, predicate, options);
100-
}
94+
return new Argument(description, predicate, options)
95+
}
10196

102-
const anyArgFunction: Inversable<Any> = (type) => factory(anyFunction)(type);
103-
anyArgFunction.not = (type) => factory(anyFunction)(type, { inverseMatch: true });
104-
export const any = anyArgFunction;
97+
export const any = createInversable(anyFunction) as Inversable<Any>
10598
}

0 commit comments

Comments
 (0)