11type PredicateFunction < T > = ( arg : T ) => boolean
22type ArgumentOptions = {
3- inverseMatch ?: boolean
3+ inverseMatch ?: boolean
44}
55class 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
2626export 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
3633export 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
4643export 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