@@ -125,7 +125,7 @@ export abstract class SchemaElement<TParent extends SchemaElement<any, any> | Sc
125
125
}
126
126
127
127
appliedDirectivesOf ( name : string ) : Directive [ ] ;
128
- appliedDirectivesOf ( definition : DirectiveDefinition ) : Directive [ ] ;
128
+ appliedDirectivesOf < TApplicationArgs extends { [ key : string ] : any } = { [ key : string ] : any } > ( definition : DirectiveDefinition < TApplicationArgs > ) : Directive < TApplicationArgs > [ ] ;
129
129
appliedDirectivesOf ( nameOrDefinition : string | DirectiveDefinition ) : Directive [ ] {
130
130
const directiveName = typeof nameOrDefinition === 'string' ? nameOrDefinition : nameOrDefinition . name ;
131
131
return this . _appliedDirectives . filter ( d => d . name == directiveName ) ;
@@ -156,6 +156,7 @@ export abstract class SchemaElement<TParent extends SchemaElement<any, any> | Sc
156
156
Directive . prototype [ 'setParent' ] . call ( toAdd , this ) ;
157
157
toAdd . source = source ;
158
158
}
159
+ // TODO: we should typecheck arguments or our TApplicationArgs business is just a lie.
159
160
this . _appliedDirectives . push ( toAdd ) ;
160
161
DirectiveDefinition . prototype [ 'addReferencer' ] . call ( toAdd . definition ! , toAdd ) ;
161
162
return toAdd ;
@@ -351,6 +352,33 @@ export class BuiltIns {
351
352
protected addBuiltInDirective ( schema : Schema , name : string ) : DirectiveDefinition {
352
353
return schema . addDirectiveDefinition ( new DirectiveDefinition ( name , true ) ) ;
353
354
}
355
+
356
+ protected getTypedDirective < TApplicationArgs extends { [ key : string ] : any } > (
357
+ schema : Schema ,
358
+ name : string
359
+ ) : DirectiveDefinition < TApplicationArgs > {
360
+ const directive = schema . directive ( name ) ;
361
+ if ( ! directive ) {
362
+ throw new Error ( `The provided schema has not be built with the ${ name } directive built-in` ) ;
363
+ }
364
+ return directive as DirectiveDefinition < TApplicationArgs > ;
365
+ }
366
+
367
+ includeDirective ( schema : Schema ) : DirectiveDefinition < { if : boolean } > {
368
+ return this . getTypedDirective ( schema , 'include' ) ;
369
+ }
370
+
371
+ skipDirective ( schema : Schema ) : DirectiveDefinition < { if : boolean } > {
372
+ return this . getTypedDirective ( schema , 'skip' ) ;
373
+ }
374
+
375
+ deprecatedDirective ( schema : Schema ) : DirectiveDefinition < { reason ?: string } > {
376
+ return this . getTypedDirective ( schema , 'deprecated' ) ;
377
+ }
378
+
379
+ specifiedByDirective ( schema : Schema ) : DirectiveDefinition < { url : string } > {
380
+ return this . getTypedDirective ( schema , 'specifiedBy' ) ;
381
+ }
354
382
}
355
383
356
384
export class Schema {
@@ -1054,13 +1082,13 @@ export class EnumValue extends BaseNamedElement<EnumType, never> {
1054
1082
}
1055
1083
}
1056
1084
1057
- export class DirectiveDefinition extends BaseNamedElement < Schema , Directive > {
1085
+ export class DirectiveDefinition < TApplicationArgs extends { [ key : string ] : any } = { [ key : string ] : any } > extends BaseNamedElement < Schema , Directive > {
1058
1086
readonly kind : 'DirectiveDefinition' = 'DirectiveDefinition' ;
1059
1087
1060
1088
private readonly _args : Map < string , ArgumentDefinition < DirectiveDefinition > > = new Map ( ) ;
1061
1089
repeatable : boolean = false ;
1062
1090
private readonly _locations : DirectiveLocationEnum [ ] = [ ] ;
1063
- private readonly _referencers : Set < Directive > = new Set ( ) ;
1091
+ private readonly _referencers : Set < Directive < TApplicationArgs > > = new Set ( ) ;
1064
1092
1065
1093
constructor ( name : string , readonly isBuiltIn : boolean = false ) {
1066
1094
super ( name ) ;
@@ -1132,7 +1160,7 @@ export class DirectiveDefinition extends BaseNamedElement<Schema, Directive> {
1132
1160
return this ;
1133
1161
}
1134
1162
1135
- private addReferencer ( referencer : Directive ) {
1163
+ private addReferencer ( referencer : Directive < TApplicationArgs > ) {
1136
1164
assert ( referencer , 'Referencer should exists' ) ;
1137
1165
this . _referencers . add ( referencer ) ;
1138
1166
}
@@ -1170,11 +1198,11 @@ export class DirectiveDefinition extends BaseNamedElement<Schema, Directive> {
1170
1198
// value if `x` has one and wasn't explicitly set in the application. This would make code usage more pleasant. Should
1171
1199
// `arguments()` also return those though? Maybe have an option to both method to say if it should include them or not.
1172
1200
// (The question stands for matchArguments() as well though).
1173
- export class Directive implements Named {
1201
+ export class Directive < TArgs extends { [ key : string ] : any } = { [ key : string ] : any } > implements Named {
1174
1202
private _parent ?: SchemaElement < any , any > ;
1175
1203
source ?: ASTNode ;
1176
1204
1177
- constructor ( readonly name : string , private _args : Record < string , any > ) { }
1205
+ constructor ( readonly name : string , private _args : TArgs ) { }
1178
1206
1179
1207
schema ( ) : Schema | undefined {
1180
1208
return this . _parent ?. schema ( ) ;
@@ -1194,14 +1222,10 @@ export class Directive implements Named {
1194
1222
return doc ?. directive ( this . name ) ;
1195
1223
}
1196
1224
1197
- get arguments ( ) : Record < string , any > {
1225
+ get arguments ( ) : TArgs {
1198
1226
return this . _args ;
1199
1227
}
1200
1228
1201
- argument ( name : string ) : any {
1202
- return this . _args . get ( name ) ;
1203
- }
1204
-
1205
1229
matchArguments ( expectedArgs : Record < string , any > ) : boolean {
1206
1230
const entries = Object . entries ( this . _args ) ;
1207
1231
if ( entries . length !== Object . keys ( expectedArgs ) . length ) {
0 commit comments