You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
77 lines
2.6 KiB
77 lines
2.6 KiB
import { GraphQLError } from '../../error/GraphQLError.mjs'; |
|
import { Kind } from '../../language/kinds.mjs'; |
|
import { collectFields } from '../../execution/collectFields.mjs'; |
|
|
|
/** |
|
* Subscriptions must only include a non-introspection field. |
|
* |
|
* A GraphQL subscription is valid only if it contains a single root field and |
|
* that root field is not an introspection field. |
|
* |
|
* See https://spec.graphql.org/draft/#sec-Single-root-field |
|
*/ |
|
export function SingleFieldSubscriptionsRule(context) { |
|
return { |
|
OperationDefinition(node) { |
|
if (node.operation === 'subscription') { |
|
const schema = context.getSchema(); |
|
const subscriptionType = schema.getSubscriptionType(); |
|
|
|
if (subscriptionType) { |
|
const operationName = node.name ? node.name.value : null; |
|
const variableValues = Object.create(null); |
|
const document = context.getDocument(); |
|
const fragments = Object.create(null); |
|
|
|
for (const definition of document.definitions) { |
|
if (definition.kind === Kind.FRAGMENT_DEFINITION) { |
|
fragments[definition.name.value] = definition; |
|
} |
|
} |
|
|
|
const fields = collectFields( |
|
schema, |
|
fragments, |
|
variableValues, |
|
subscriptionType, |
|
node.selectionSet, |
|
); |
|
|
|
if (fields.size > 1) { |
|
const fieldSelectionLists = [...fields.values()]; |
|
const extraFieldSelectionLists = fieldSelectionLists.slice(1); |
|
const extraFieldSelections = extraFieldSelectionLists.flat(); |
|
context.reportError( |
|
new GraphQLError( |
|
operationName != null |
|
? `Subscription "${operationName}" must select only one top level field.` |
|
: 'Anonymous Subscription must select only one top level field.', |
|
{ |
|
nodes: extraFieldSelections, |
|
}, |
|
), |
|
); |
|
} |
|
|
|
for (const fieldNodes of fields.values()) { |
|
const field = fieldNodes[0]; |
|
const fieldName = field.name.value; |
|
|
|
if (fieldName.startsWith('__')) { |
|
context.reportError( |
|
new GraphQLError( |
|
operationName != null |
|
? `Subscription "${operationName}" must not select an introspection top level field.` |
|
: 'Anonymous Subscription must not select an introspection top level field.', |
|
{ |
|
nodes: fieldNodes, |
|
}, |
|
), |
|
); |
|
} |
|
} |
|
} |
|
} |
|
}, |
|
}; |
|
}
|
|
|