variablesInAllowedPositionRule function
Visitor
variablesInAllowedPositionRule(
- ValidationCtx context
Variables in allowed position
Variable usages must be compatible with the arguments they are passed to.
See https://spec.graphql.org/draft/#sec-All-Variable-Usages-are-Allowed
Implementation
Visitor variablesInAllowedPositionRule(
ValidationCtx context,
) {
final visitor = TypedVisitor();
var varDefMap = <String, VariableDefinitionNode>{};
visitor.add<VariableDefinitionNode>((node) {
varDefMap[node.variable.name.value] = node;
});
visitor.add<OperationDefinitionNode>((node) {
varDefMap = {};
}, leave: (operation) {
final usages = context.getRecursiveVariableUsages(operation);
for (final usage in usages) {
final node = usage.node;
final varName = node.name.value;
final varDef = varDefMap[varName];
if (varDef != null && usage.type != null) {
// A var type is allowed if it is the same or more strict (e.g. is
// a subtype of) than the expected type. It can be more strict if
// the variable type is non-null when the expected type is nullable.
// If both are list types, the variable item type can be more strict
// than the expected item type (contravariant).
final schema = context.schema;
final varType = convertTypeOrNull(varDef.type, schema.typeMap);
if (varType != null &&
!allowedVariableUsage(
schema,
varType,
varDef.defaultValue?.value,
usage.type!,
usage.defaultValue,
)) {
final varTypeStr = inspect(varType);
final typeStr = inspect(usage.type!);
context.reportError(
GraphQLError(
'Variable "\$${varName}" of type "${varTypeStr}" used'
' in position expecting type "${typeStr}".',
locations: List.of(<Node?>[
varDef,
varDef.variable,
varDef.variable.name,
node,
node.name
]
.map((e) => e?.span == null
? null
: GraphQLErrorLocation.fromSourceLocation(e!.span!.start))
.whereType<GraphQLErrorLocation>()),
extensions: _variablesInAllowedPositionSpec.extensions(),
),
);
}
}
}
});
return visitor;
}