Initial Sample.

This commit is contained in:
2024-06-03 20:23:50 +05:30
parent ef2b65f673
commit 5269ec3c66
2575 changed files with 282312 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
import type { ObjMap } from '../jsutils/ObjMap';
import type {
FieldNode,
FragmentDefinitionNode,
SelectionSetNode,
} from '../language/ast';
import type { GraphQLObjectType } from '../type/definition';
import type { GraphQLSchema } from '../type/schema';
/**
* Given a selectionSet, collects all of the fields and returns them.
*
* CollectFields requires the "runtime type" of an object. For a field that
* returns an Interface or Union type, the "runtime type" will be the actual
* object type returned by that field.
*
* @internal
*/
export declare function collectFields(
schema: GraphQLSchema,
fragments: ObjMap<FragmentDefinitionNode>,
variableValues: {
[variable: string]: unknown;
},
runtimeType: GraphQLObjectType,
selectionSet: SelectionSetNode,
): Map<string, ReadonlyArray<FieldNode>>;
/**
* Given an array of field nodes, collects all of the subfields of the passed
* in fields, and returns them at the end.
*
* CollectSubFields requires the "return type" of an object. For a field that
* returns an Interface or Union type, the "return type" will be the actual
* object type returned by that field.
*
* @internal
*/
export declare function collectSubfields(
schema: GraphQLSchema,
fragments: ObjMap<FragmentDefinitionNode>,
variableValues: {
[variable: string]: unknown;
},
returnType: GraphQLObjectType,
fieldNodes: ReadonlyArray<FieldNode>,
): Map<string, ReadonlyArray<FieldNode>>;

View File

@@ -0,0 +1,229 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.collectFields = collectFields;
exports.collectSubfields = collectSubfields;
var _kinds = require('../language/kinds.js');
var _definition = require('../type/definition.js');
var _directives = require('../type/directives.js');
var _typeFromAST = require('../utilities/typeFromAST.js');
var _values = require('./values.js');
/**
* Given a selectionSet, collects all of the fields and returns them.
*
* CollectFields requires the "runtime type" of an object. For a field that
* returns an Interface or Union type, the "runtime type" will be the actual
* object type returned by that field.
*
* @internal
*/
function collectFields(
schema,
fragments,
variableValues,
runtimeType,
selectionSet,
) {
const fields = new Map();
collectFieldsImpl(
schema,
fragments,
variableValues,
runtimeType,
selectionSet,
fields,
new Set(),
);
return fields;
}
/**
* Given an array of field nodes, collects all of the subfields of the passed
* in fields, and returns them at the end.
*
* CollectSubFields requires the "return type" of an object. For a field that
* returns an Interface or Union type, the "return type" will be the actual
* object type returned by that field.
*
* @internal
*/
function collectSubfields(
schema,
fragments,
variableValues,
returnType,
fieldNodes,
) {
const subFieldNodes = new Map();
const visitedFragmentNames = new Set();
for (const node of fieldNodes) {
if (node.selectionSet) {
collectFieldsImpl(
schema,
fragments,
variableValues,
returnType,
node.selectionSet,
subFieldNodes,
visitedFragmentNames,
);
}
}
return subFieldNodes;
}
function collectFieldsImpl(
schema,
fragments,
variableValues,
runtimeType,
selectionSet,
fields,
visitedFragmentNames,
) {
for (const selection of selectionSet.selections) {
switch (selection.kind) {
case _kinds.Kind.FIELD: {
if (!shouldIncludeNode(variableValues, selection)) {
continue;
}
const name = getFieldEntryKey(selection);
const fieldList = fields.get(name);
if (fieldList !== undefined) {
fieldList.push(selection);
} else {
fields.set(name, [selection]);
}
break;
}
case _kinds.Kind.INLINE_FRAGMENT: {
if (
!shouldIncludeNode(variableValues, selection) ||
!doesFragmentConditionMatch(schema, selection, runtimeType)
) {
continue;
}
collectFieldsImpl(
schema,
fragments,
variableValues,
runtimeType,
selection.selectionSet,
fields,
visitedFragmentNames,
);
break;
}
case _kinds.Kind.FRAGMENT_SPREAD: {
const fragName = selection.name.value;
if (
visitedFragmentNames.has(fragName) ||
!shouldIncludeNode(variableValues, selection)
) {
continue;
}
visitedFragmentNames.add(fragName);
const fragment = fragments[fragName];
if (
!fragment ||
!doesFragmentConditionMatch(schema, fragment, runtimeType)
) {
continue;
}
collectFieldsImpl(
schema,
fragments,
variableValues,
runtimeType,
fragment.selectionSet,
fields,
visitedFragmentNames,
);
break;
}
}
}
}
/**
* Determines if a field should be included based on the `@include` and `@skip`
* directives, where `@skip` has higher precedence than `@include`.
*/
function shouldIncludeNode(variableValues, node) {
const skip = (0, _values.getDirectiveValues)(
_directives.GraphQLSkipDirective,
node,
variableValues,
);
if ((skip === null || skip === void 0 ? void 0 : skip.if) === true) {
return false;
}
const include = (0, _values.getDirectiveValues)(
_directives.GraphQLIncludeDirective,
node,
variableValues,
);
if (
(include === null || include === void 0 ? void 0 : include.if) === false
) {
return false;
}
return true;
}
/**
* Determines if a fragment is applicable to the given type.
*/
function doesFragmentConditionMatch(schema, fragment, type) {
const typeConditionNode = fragment.typeCondition;
if (!typeConditionNode) {
return true;
}
const conditionalType = (0, _typeFromAST.typeFromAST)(
schema,
typeConditionNode,
);
if (conditionalType === type) {
return true;
}
if ((0, _definition.isAbstractType)(conditionalType)) {
return schema.isSubType(conditionalType, type);
}
return false;
}
/**
* Implements the logic to compute the key of a given field's entry
*/
function getFieldEntryKey(node) {
return node.alias ? node.alias.value : node.name.value;
}

View File

@@ -0,0 +1,213 @@
import { Kind } from '../language/kinds.mjs';
import { isAbstractType } from '../type/definition.mjs';
import {
GraphQLIncludeDirective,
GraphQLSkipDirective,
} from '../type/directives.mjs';
import { typeFromAST } from '../utilities/typeFromAST.mjs';
import { getDirectiveValues } from './values.mjs';
/**
* Given a selectionSet, collects all of the fields and returns them.
*
* CollectFields requires the "runtime type" of an object. For a field that
* returns an Interface or Union type, the "runtime type" will be the actual
* object type returned by that field.
*
* @internal
*/
export function collectFields(
schema,
fragments,
variableValues,
runtimeType,
selectionSet,
) {
const fields = new Map();
collectFieldsImpl(
schema,
fragments,
variableValues,
runtimeType,
selectionSet,
fields,
new Set(),
);
return fields;
}
/**
* Given an array of field nodes, collects all of the subfields of the passed
* in fields, and returns them at the end.
*
* CollectSubFields requires the "return type" of an object. For a field that
* returns an Interface or Union type, the "return type" will be the actual
* object type returned by that field.
*
* @internal
*/
export function collectSubfields(
schema,
fragments,
variableValues,
returnType,
fieldNodes,
) {
const subFieldNodes = new Map();
const visitedFragmentNames = new Set();
for (const node of fieldNodes) {
if (node.selectionSet) {
collectFieldsImpl(
schema,
fragments,
variableValues,
returnType,
node.selectionSet,
subFieldNodes,
visitedFragmentNames,
);
}
}
return subFieldNodes;
}
function collectFieldsImpl(
schema,
fragments,
variableValues,
runtimeType,
selectionSet,
fields,
visitedFragmentNames,
) {
for (const selection of selectionSet.selections) {
switch (selection.kind) {
case Kind.FIELD: {
if (!shouldIncludeNode(variableValues, selection)) {
continue;
}
const name = getFieldEntryKey(selection);
const fieldList = fields.get(name);
if (fieldList !== undefined) {
fieldList.push(selection);
} else {
fields.set(name, [selection]);
}
break;
}
case Kind.INLINE_FRAGMENT: {
if (
!shouldIncludeNode(variableValues, selection) ||
!doesFragmentConditionMatch(schema, selection, runtimeType)
) {
continue;
}
collectFieldsImpl(
schema,
fragments,
variableValues,
runtimeType,
selection.selectionSet,
fields,
visitedFragmentNames,
);
break;
}
case Kind.FRAGMENT_SPREAD: {
const fragName = selection.name.value;
if (
visitedFragmentNames.has(fragName) ||
!shouldIncludeNode(variableValues, selection)
) {
continue;
}
visitedFragmentNames.add(fragName);
const fragment = fragments[fragName];
if (
!fragment ||
!doesFragmentConditionMatch(schema, fragment, runtimeType)
) {
continue;
}
collectFieldsImpl(
schema,
fragments,
variableValues,
runtimeType,
fragment.selectionSet,
fields,
visitedFragmentNames,
);
break;
}
}
}
}
/**
* Determines if a field should be included based on the `@include` and `@skip`
* directives, where `@skip` has higher precedence than `@include`.
*/
function shouldIncludeNode(variableValues, node) {
const skip = getDirectiveValues(GraphQLSkipDirective, node, variableValues);
if ((skip === null || skip === void 0 ? void 0 : skip.if) === true) {
return false;
}
const include = getDirectiveValues(
GraphQLIncludeDirective,
node,
variableValues,
);
if (
(include === null || include === void 0 ? void 0 : include.if) === false
) {
return false;
}
return true;
}
/**
* Determines if a fragment is applicable to the given type.
*/
function doesFragmentConditionMatch(schema, fragment, type) {
const typeConditionNode = fragment.typeCondition;
if (!typeConditionNode) {
return true;
}
const conditionalType = typeFromAST(schema, typeConditionNode);
if (conditionalType === type) {
return true;
}
if (isAbstractType(conditionalType)) {
return schema.isSubType(conditionalType, type);
}
return false;
}
/**
* Implements the logic to compute the key of a given field's entry
*/
function getFieldEntryKey(node) {
return node.alias ? node.alias.value : node.name.value;
}

View File

@@ -0,0 +1,185 @@
import type { Maybe } from '../jsutils/Maybe';
import type { ObjMap } from '../jsutils/ObjMap';
import type { Path } from '../jsutils/Path';
import type { PromiseOrValue } from '../jsutils/PromiseOrValue';
import type { GraphQLFormattedError } from '../error/GraphQLError';
import { GraphQLError } from '../error/GraphQLError';
import type {
DocumentNode,
FieldNode,
FragmentDefinitionNode,
OperationDefinitionNode,
} from '../language/ast';
import type {
GraphQLField,
GraphQLFieldResolver,
GraphQLObjectType,
GraphQLResolveInfo,
GraphQLTypeResolver,
} from '../type/definition';
import type { GraphQLSchema } from '../type/schema';
/**
* Terminology
*
* "Definitions" are the generic name for top-level statements in the document.
* Examples of this include:
* 1) Operations (such as a query)
* 2) Fragments
*
* "Operations" are a generic name for requests in the document.
* Examples of this include:
* 1) query,
* 2) mutation
*
* "Selections" are the definitions that can appear legally and at
* single level of the query. These include:
* 1) field references e.g `a`
* 2) fragment "spreads" e.g. `...c`
* 3) inline fragment "spreads" e.g. `...on Type { a }`
*/
/**
* Data that must be available at all points during query execution.
*
* Namely, schema of the type system that is currently executing,
* and the fragments defined in the query document
*/
export interface ExecutionContext {
schema: GraphQLSchema;
fragments: ObjMap<FragmentDefinitionNode>;
rootValue: unknown;
contextValue: unknown;
operation: OperationDefinitionNode;
variableValues: {
[variable: string]: unknown;
};
fieldResolver: GraphQLFieldResolver<any, any>;
typeResolver: GraphQLTypeResolver<any, any>;
subscribeFieldResolver: GraphQLFieldResolver<any, any>;
errors: Array<GraphQLError>;
}
/**
* The result of GraphQL execution.
*
* - `errors` is included when any errors occurred as a non-empty array.
* - `data` is the result of a successful execution of the query.
* - `extensions` is reserved for adding non-standard properties.
*/
export interface ExecutionResult<
TData = ObjMap<unknown>,
TExtensions = ObjMap<unknown>,
> {
errors?: ReadonlyArray<GraphQLError>;
data?: TData | null;
extensions?: TExtensions;
}
export interface FormattedExecutionResult<
TData = ObjMap<unknown>,
TExtensions = ObjMap<unknown>,
> {
errors?: ReadonlyArray<GraphQLFormattedError>;
data?: TData | null;
extensions?: TExtensions;
}
export interface ExecutionArgs {
schema: GraphQLSchema;
document: DocumentNode;
rootValue?: unknown;
contextValue?: unknown;
variableValues?: Maybe<{
readonly [variable: string]: unknown;
}>;
operationName?: Maybe<string>;
fieldResolver?: Maybe<GraphQLFieldResolver<any, any>>;
typeResolver?: Maybe<GraphQLTypeResolver<any, any>>;
subscribeFieldResolver?: Maybe<GraphQLFieldResolver<any, any>>;
}
/**
* Implements the "Executing requests" section of the GraphQL specification.
*
* Returns either a synchronous ExecutionResult (if all encountered resolvers
* are synchronous), or a Promise of an ExecutionResult that will eventually be
* resolved and never rejected.
*
* If the arguments to this function do not result in a legal execution context,
* a GraphQLError will be thrown immediately explaining the invalid input.
*/
export declare function execute(
args: ExecutionArgs,
): PromiseOrValue<ExecutionResult>;
/**
* Also implements the "Executing requests" section of the GraphQL specification.
* However, it guarantees to complete synchronously (or throw an error) assuming
* that all field resolvers are also synchronous.
*/
export declare function executeSync(args: ExecutionArgs): ExecutionResult;
/**
* Essential assertions before executing to provide developer feedback for
* improper use of the GraphQL library.
*
* @internal
*/
export declare function assertValidExecutionArguments(
schema: GraphQLSchema,
document: DocumentNode,
rawVariableValues: Maybe<{
readonly [variable: string]: unknown;
}>,
): void;
/**
* Constructs a ExecutionContext object from the arguments passed to
* execute, which we will pass throughout the other execution methods.
*
* Throws a GraphQLError if a valid execution context cannot be created.
*
* @internal
*/
export declare function buildExecutionContext(
args: ExecutionArgs,
): ReadonlyArray<GraphQLError> | ExecutionContext;
/**
* @internal
*/
export declare function buildResolveInfo(
exeContext: ExecutionContext,
fieldDef: GraphQLField<unknown, unknown>,
fieldNodes: ReadonlyArray<FieldNode>,
parentType: GraphQLObjectType,
path: Path,
): GraphQLResolveInfo;
/**
* If a resolveType function is not given, then a default resolve behavior is
* used which attempts two strategies:
*
* First, See if the provided value has a `__typename` field defined, if so, use
* that value as name of the resolved type.
*
* Otherwise, test each possible type for the abstract type by calling
* isTypeOf for the object being coerced, returning the first type that matches.
*/
export declare const defaultTypeResolver: GraphQLTypeResolver<unknown, unknown>;
/**
* If a resolve function is not given, then a default resolve behavior is used
* which takes the property of the source object of the same name as the field
* and returns it as the result, or if it's a function, returns the result
* of calling that function while passing along args and context value.
*/
export declare const defaultFieldResolver: GraphQLFieldResolver<
unknown,
unknown
>;
/**
* This method looks up the field on the given type definition.
* It has special casing for the three introspection fields,
* __schema, __type and __typename. __typename is special because
* it can always be queried as a field, even in situations where no
* other fields are allowed, like on a Union. __schema and __type
* could get automatically added to the query type, but that would
* require mutating type definitions, which would cause issues.
*
* @internal
*/
export declare function getFieldDef(
schema: GraphQLSchema,
parentType: GraphQLObjectType,
fieldNode: FieldNode,
): Maybe<GraphQLField<unknown, unknown>>;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
export { pathToArray as responsePathAsArray } from '../jsutils/Path';
export {
execute,
executeSync,
defaultFieldResolver,
defaultTypeResolver,
} from './execute';
export type {
ExecutionArgs,
ExecutionResult,
FormattedExecutionResult,
} from './execute';
export { subscribe, createSourceEventStream } from './subscribe';
export {
getArgumentValues,
getVariableValues,
getDirectiveValues,
} from './values';

View File

@@ -0,0 +1,73 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
Object.defineProperty(exports, 'createSourceEventStream', {
enumerable: true,
get: function () {
return _subscribe.createSourceEventStream;
},
});
Object.defineProperty(exports, 'defaultFieldResolver', {
enumerable: true,
get: function () {
return _execute.defaultFieldResolver;
},
});
Object.defineProperty(exports, 'defaultTypeResolver', {
enumerable: true,
get: function () {
return _execute.defaultTypeResolver;
},
});
Object.defineProperty(exports, 'execute', {
enumerable: true,
get: function () {
return _execute.execute;
},
});
Object.defineProperty(exports, 'executeSync', {
enumerable: true,
get: function () {
return _execute.executeSync;
},
});
Object.defineProperty(exports, 'getArgumentValues', {
enumerable: true,
get: function () {
return _values.getArgumentValues;
},
});
Object.defineProperty(exports, 'getDirectiveValues', {
enumerable: true,
get: function () {
return _values.getDirectiveValues;
},
});
Object.defineProperty(exports, 'getVariableValues', {
enumerable: true,
get: function () {
return _values.getVariableValues;
},
});
Object.defineProperty(exports, 'responsePathAsArray', {
enumerable: true,
get: function () {
return _Path.pathToArray;
},
});
Object.defineProperty(exports, 'subscribe', {
enumerable: true,
get: function () {
return _subscribe.subscribe;
},
});
var _Path = require('../jsutils/Path.js');
var _execute = require('./execute.js');
var _subscribe = require('./subscribe.js');
var _values = require('./values.js');

View File

@@ -0,0 +1,13 @@
export { pathToArray as responsePathAsArray } from '../jsutils/Path.mjs';
export {
execute,
executeSync,
defaultFieldResolver,
defaultTypeResolver,
} from './execute.mjs';
export { subscribe, createSourceEventStream } from './subscribe.mjs';
export {
getArgumentValues,
getVariableValues,
getDirectiveValues,
} from './values.mjs';

View File

@@ -0,0 +1,9 @@
import type { PromiseOrValue } from '../jsutils/PromiseOrValue';
/**
* Given an AsyncIterable and a callback function, return an AsyncIterator
* which produces values mapped via calling the callback function.
*/
export declare function mapAsyncIterator<T, U, R = undefined>(
iterable: AsyncGenerator<T, R, void> | AsyncIterable<T>,
callback: (value: T) => PromiseOrValue<U>,
): AsyncGenerator<U, R, void>;

View File

@@ -0,0 +1,68 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.mapAsyncIterator = mapAsyncIterator;
/**
* Given an AsyncIterable and a callback function, return an AsyncIterator
* which produces values mapped via calling the callback function.
*/
function mapAsyncIterator(iterable, callback) {
const iterator = iterable[Symbol.asyncIterator]();
async function mapResult(result) {
if (result.done) {
return result;
}
try {
return {
value: await callback(result.value),
done: false,
};
} catch (error) {
/* c8 ignore start */
// FIXME: add test case
if (typeof iterator.return === 'function') {
try {
await iterator.return();
} catch (_e) {
/* ignore error */
}
}
throw error;
/* c8 ignore stop */
}
}
return {
async next() {
return mapResult(await iterator.next());
},
async return() {
// If iterator.return() does not exist, then type R must be undefined.
return typeof iterator.return === 'function'
? mapResult(await iterator.return())
: {
value: undefined,
done: true,
};
},
async throw(error) {
if (typeof iterator.throw === 'function') {
return mapResult(await iterator.throw(error));
}
throw error;
},
[Symbol.asyncIterator]() {
return this;
},
};
}

View File

@@ -0,0 +1,61 @@
/**
* Given an AsyncIterable and a callback function, return an AsyncIterator
* which produces values mapped via calling the callback function.
*/
export function mapAsyncIterator(iterable, callback) {
const iterator = iterable[Symbol.asyncIterator]();
async function mapResult(result) {
if (result.done) {
return result;
}
try {
return {
value: await callback(result.value),
done: false,
};
} catch (error) {
/* c8 ignore start */
// FIXME: add test case
if (typeof iterator.return === 'function') {
try {
await iterator.return();
} catch (_e) {
/* ignore error */
}
}
throw error;
/* c8 ignore stop */
}
}
return {
async next() {
return mapResult(await iterator.next());
},
async return() {
// If iterator.return() does not exist, then type R must be undefined.
return typeof iterator.return === 'function'
? mapResult(await iterator.return())
: {
value: undefined,
done: true,
};
},
async throw(error) {
if (typeof iterator.throw === 'function') {
return mapResult(await iterator.throw(error));
}
throw error;
},
[Symbol.asyncIterator]() {
return this;
},
};
}

View File

@@ -0,0 +1,72 @@
import type { Maybe } from '../jsutils/Maybe';
import type { DocumentNode } from '../language/ast';
import type { GraphQLFieldResolver } from '../type/definition';
import type { GraphQLSchema } from '../type/schema';
import type { ExecutionArgs, ExecutionResult } from './execute';
/**
* Implements the "Subscribe" algorithm described in the GraphQL specification.
*
* Returns a Promise which resolves to either an AsyncIterator (if successful)
* or an ExecutionResult (error). The promise will be rejected if the schema or
* other arguments to this function are invalid, or if the resolved event stream
* is not an async iterable.
*
* If the client-provided arguments to this function do not result in a
* compliant subscription, a GraphQL Response (ExecutionResult) with
* descriptive errors and no data will be returned.
*
* If the source stream could not be created due to faulty subscription
* resolver logic or underlying systems, the promise will resolve to a single
* ExecutionResult containing `errors` and no `data`.
*
* If the operation succeeded, the promise resolves to an AsyncIterator, which
* yields a stream of ExecutionResults representing the response stream.
*
* Accepts either an object with named arguments, or individual arguments.
*/
export declare function subscribe(
args: ExecutionArgs,
): Promise<AsyncGenerator<ExecutionResult, void, void> | ExecutionResult>;
/**
* Implements the "CreateSourceEventStream" algorithm described in the
* GraphQL specification, resolving the subscription source event stream.
*
* Returns a Promise which resolves to either an AsyncIterable (if successful)
* or an ExecutionResult (error). The promise will be rejected if the schema or
* other arguments to this function are invalid, or if the resolved event stream
* is not an async iterable.
*
* If the client-provided arguments to this function do not result in a
* compliant subscription, a GraphQL Response (ExecutionResult) with
* descriptive errors and no data will be returned.
*
* If the the source stream could not be created due to faulty subscription
* resolver logic or underlying systems, the promise will resolve to a single
* ExecutionResult containing `errors` and no `data`.
*
* If the operation succeeded, the promise resolves to the AsyncIterable for the
* event stream returned by the resolver.
*
* A Source Event Stream represents a sequence of events, each of which triggers
* a GraphQL execution for that event.
*
* This may be useful when hosting the stateful subscription service in a
* different process or machine than the stateless GraphQL execution engine,
* or otherwise separating these two steps. For more on this, see the
* "Supporting Subscriptions at Scale" information in the GraphQL specification.
*/
export declare function createSourceEventStream(
args: ExecutionArgs,
): Promise<AsyncIterable<unknown> | ExecutionResult>;
/** @deprecated will be removed in next major version in favor of named arguments */
export declare function createSourceEventStream(
schema: GraphQLSchema,
document: DocumentNode,
rootValue?: unknown,
contextValue?: unknown,
variableValues?: Maybe<{
readonly [variable: string]: unknown;
}>,
operationName?: Maybe<string>,
subscribeFieldResolver?: Maybe<GraphQLFieldResolver<any, any>>,
): Promise<AsyncIterable<unknown> | ExecutionResult>;

View File

@@ -0,0 +1,244 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.createSourceEventStream = createSourceEventStream;
exports.subscribe = subscribe;
var _devAssert = require('../jsutils/devAssert.js');
var _inspect = require('../jsutils/inspect.js');
var _isAsyncIterable = require('../jsutils/isAsyncIterable.js');
var _Path = require('../jsutils/Path.js');
var _GraphQLError = require('../error/GraphQLError.js');
var _locatedError = require('../error/locatedError.js');
var _collectFields = require('./collectFields.js');
var _execute = require('./execute.js');
var _mapAsyncIterator = require('./mapAsyncIterator.js');
var _values = require('./values.js');
/**
* Implements the "Subscribe" algorithm described in the GraphQL specification.
*
* Returns a Promise which resolves to either an AsyncIterator (if successful)
* or an ExecutionResult (error). The promise will be rejected if the schema or
* other arguments to this function are invalid, or if the resolved event stream
* is not an async iterable.
*
* If the client-provided arguments to this function do not result in a
* compliant subscription, a GraphQL Response (ExecutionResult) with
* descriptive errors and no data will be returned.
*
* If the source stream could not be created due to faulty subscription
* resolver logic or underlying systems, the promise will resolve to a single
* ExecutionResult containing `errors` and no `data`.
*
* If the operation succeeded, the promise resolves to an AsyncIterator, which
* yields a stream of ExecutionResults representing the response stream.
*
* Accepts either an object with named arguments, or individual arguments.
*/
async function subscribe(args) {
// Temporary for v15 to v16 migration. Remove in v17
arguments.length < 2 ||
(0, _devAssert.devAssert)(
false,
'graphql@16 dropped long-deprecated support for positional arguments, please pass an object instead.',
);
const resultOrStream = await createSourceEventStream(args);
if (!(0, _isAsyncIterable.isAsyncIterable)(resultOrStream)) {
return resultOrStream;
} // For each payload yielded from a subscription, map it over the normal
// GraphQL `execute` function, with `payload` as the rootValue.
// This implements the "MapSourceToResponseEvent" algorithm described in
// the GraphQL specification. The `execute` function provides the
// "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the
// "ExecuteQuery" algorithm, for which `execute` is also used.
const mapSourceToResponse = (payload) =>
(0, _execute.execute)({ ...args, rootValue: payload }); // Map every source value to a ExecutionResult value as described above.
return (0, _mapAsyncIterator.mapAsyncIterator)(
resultOrStream,
mapSourceToResponse,
);
}
function toNormalizedArgs(args) {
const firstArg = args[0];
if (firstArg && 'document' in firstArg) {
return firstArg;
}
return {
schema: firstArg,
// FIXME: when underlying TS bug fixed, see https://github.com/microsoft/TypeScript/issues/31613
document: args[1],
rootValue: args[2],
contextValue: args[3],
variableValues: args[4],
operationName: args[5],
subscribeFieldResolver: args[6],
};
}
/**
* Implements the "CreateSourceEventStream" algorithm described in the
* GraphQL specification, resolving the subscription source event stream.
*
* Returns a Promise which resolves to either an AsyncIterable (if successful)
* or an ExecutionResult (error). The promise will be rejected if the schema or
* other arguments to this function are invalid, or if the resolved event stream
* is not an async iterable.
*
* If the client-provided arguments to this function do not result in a
* compliant subscription, a GraphQL Response (ExecutionResult) with
* descriptive errors and no data will be returned.
*
* If the the source stream could not be created due to faulty subscription
* resolver logic or underlying systems, the promise will resolve to a single
* ExecutionResult containing `errors` and no `data`.
*
* If the operation succeeded, the promise resolves to the AsyncIterable for the
* event stream returned by the resolver.
*
* A Source Event Stream represents a sequence of events, each of which triggers
* a GraphQL execution for that event.
*
* This may be useful when hosting the stateful subscription service in a
* different process or machine than the stateless GraphQL execution engine,
* or otherwise separating these two steps. For more on this, see the
* "Supporting Subscriptions at Scale" information in the GraphQL specification.
*/
async function createSourceEventStream(...rawArgs) {
const args = toNormalizedArgs(rawArgs);
const { schema, document, variableValues } = args; // If arguments are missing or incorrectly typed, this is an internal
// developer mistake which should throw an early error.
(0, _execute.assertValidExecutionArguments)(schema, document, variableValues); // If a valid execution context cannot be created due to incorrect arguments,
// a "Response" with only errors is returned.
const exeContext = (0, _execute.buildExecutionContext)(args); // Return early errors if execution context failed.
if (!('schema' in exeContext)) {
return {
errors: exeContext,
};
}
try {
const eventStream = await executeSubscription(exeContext); // Assert field returned an event stream, otherwise yield an error.
if (!(0, _isAsyncIterable.isAsyncIterable)(eventStream)) {
throw new Error(
'Subscription field must return Async Iterable. ' +
`Received: ${(0, _inspect.inspect)(eventStream)}.`,
);
}
return eventStream;
} catch (error) {
// If it GraphQLError, report it as an ExecutionResult, containing only errors and no data.
// Otherwise treat the error as a system-class error and re-throw it.
if (error instanceof _GraphQLError.GraphQLError) {
return {
errors: [error],
};
}
throw error;
}
}
async function executeSubscription(exeContext) {
const { schema, fragments, operation, variableValues, rootValue } =
exeContext;
const rootType = schema.getSubscriptionType();
if (rootType == null) {
throw new _GraphQLError.GraphQLError(
'Schema is not configured to execute subscription operation.',
{
nodes: operation,
},
);
}
const rootFields = (0, _collectFields.collectFields)(
schema,
fragments,
variableValues,
rootType,
operation.selectionSet,
);
const [responseName, fieldNodes] = [...rootFields.entries()][0];
const fieldDef = (0, _execute.getFieldDef)(schema, rootType, fieldNodes[0]);
if (!fieldDef) {
const fieldName = fieldNodes[0].name.value;
throw new _GraphQLError.GraphQLError(
`The subscription field "${fieldName}" is not defined.`,
{
nodes: fieldNodes,
},
);
}
const path = (0, _Path.addPath)(undefined, responseName, rootType.name);
const info = (0, _execute.buildResolveInfo)(
exeContext,
fieldDef,
fieldNodes,
rootType,
path,
);
try {
var _fieldDef$subscribe;
// Implements the "ResolveFieldEventStream" algorithm from GraphQL specification.
// It differs from "ResolveFieldValue" due to providing a different `resolveFn`.
// Build a JS object of arguments from the field.arguments AST, using the
// variables scope to fulfill any variable references.
const args = (0, _values.getArgumentValues)(
fieldDef,
fieldNodes[0],
variableValues,
); // The resolve function's optional third argument is a context value that
// is provided to every resolve function within an execution. It is commonly
// used to represent an authenticated user, or request-specific caches.
const contextValue = exeContext.contextValue; // Call the `subscribe()` resolver or the default resolver to produce an
// AsyncIterable yielding raw payloads.
const resolveFn =
(_fieldDef$subscribe = fieldDef.subscribe) !== null &&
_fieldDef$subscribe !== void 0
? _fieldDef$subscribe
: exeContext.subscribeFieldResolver;
const eventStream = await resolveFn(rootValue, args, contextValue, info);
if (eventStream instanceof Error) {
throw eventStream;
}
return eventStream;
} catch (error) {
throw (0, _locatedError.locatedError)(
error,
fieldNodes,
(0, _Path.pathToArray)(path),
);
}
}

View File

@@ -0,0 +1,222 @@
import { devAssert } from '../jsutils/devAssert.mjs';
import { inspect } from '../jsutils/inspect.mjs';
import { isAsyncIterable } from '../jsutils/isAsyncIterable.mjs';
import { addPath, pathToArray } from '../jsutils/Path.mjs';
import { GraphQLError } from '../error/GraphQLError.mjs';
import { locatedError } from '../error/locatedError.mjs';
import { collectFields } from './collectFields.mjs';
import {
assertValidExecutionArguments,
buildExecutionContext,
buildResolveInfo,
execute,
getFieldDef,
} from './execute.mjs';
import { mapAsyncIterator } from './mapAsyncIterator.mjs';
import { getArgumentValues } from './values.mjs';
/**
* Implements the "Subscribe" algorithm described in the GraphQL specification.
*
* Returns a Promise which resolves to either an AsyncIterator (if successful)
* or an ExecutionResult (error). The promise will be rejected if the schema or
* other arguments to this function are invalid, or if the resolved event stream
* is not an async iterable.
*
* If the client-provided arguments to this function do not result in a
* compliant subscription, a GraphQL Response (ExecutionResult) with
* descriptive errors and no data will be returned.
*
* If the source stream could not be created due to faulty subscription
* resolver logic or underlying systems, the promise will resolve to a single
* ExecutionResult containing `errors` and no `data`.
*
* If the operation succeeded, the promise resolves to an AsyncIterator, which
* yields a stream of ExecutionResults representing the response stream.
*
* Accepts either an object with named arguments, or individual arguments.
*/
export async function subscribe(args) {
// Temporary for v15 to v16 migration. Remove in v17
arguments.length < 2 ||
devAssert(
false,
'graphql@16 dropped long-deprecated support for positional arguments, please pass an object instead.',
);
const resultOrStream = await createSourceEventStream(args);
if (!isAsyncIterable(resultOrStream)) {
return resultOrStream;
} // For each payload yielded from a subscription, map it over the normal
// GraphQL `execute` function, with `payload` as the rootValue.
// This implements the "MapSourceToResponseEvent" algorithm described in
// the GraphQL specification. The `execute` function provides the
// "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the
// "ExecuteQuery" algorithm, for which `execute` is also used.
const mapSourceToResponse = (payload) =>
execute({ ...args, rootValue: payload }); // Map every source value to a ExecutionResult value as described above.
return mapAsyncIterator(resultOrStream, mapSourceToResponse);
}
function toNormalizedArgs(args) {
const firstArg = args[0];
if (firstArg && 'document' in firstArg) {
return firstArg;
}
return {
schema: firstArg,
// FIXME: when underlying TS bug fixed, see https://github.com/microsoft/TypeScript/issues/31613
document: args[1],
rootValue: args[2],
contextValue: args[3],
variableValues: args[4],
operationName: args[5],
subscribeFieldResolver: args[6],
};
}
/**
* Implements the "CreateSourceEventStream" algorithm described in the
* GraphQL specification, resolving the subscription source event stream.
*
* Returns a Promise which resolves to either an AsyncIterable (if successful)
* or an ExecutionResult (error). The promise will be rejected if the schema or
* other arguments to this function are invalid, or if the resolved event stream
* is not an async iterable.
*
* If the client-provided arguments to this function do not result in a
* compliant subscription, a GraphQL Response (ExecutionResult) with
* descriptive errors and no data will be returned.
*
* If the the source stream could not be created due to faulty subscription
* resolver logic or underlying systems, the promise will resolve to a single
* ExecutionResult containing `errors` and no `data`.
*
* If the operation succeeded, the promise resolves to the AsyncIterable for the
* event stream returned by the resolver.
*
* A Source Event Stream represents a sequence of events, each of which triggers
* a GraphQL execution for that event.
*
* This may be useful when hosting the stateful subscription service in a
* different process or machine than the stateless GraphQL execution engine,
* or otherwise separating these two steps. For more on this, see the
* "Supporting Subscriptions at Scale" information in the GraphQL specification.
*/
export async function createSourceEventStream(...rawArgs) {
const args = toNormalizedArgs(rawArgs);
const { schema, document, variableValues } = args; // If arguments are missing or incorrectly typed, this is an internal
// developer mistake which should throw an early error.
assertValidExecutionArguments(schema, document, variableValues); // If a valid execution context cannot be created due to incorrect arguments,
// a "Response" with only errors is returned.
const exeContext = buildExecutionContext(args); // Return early errors if execution context failed.
if (!('schema' in exeContext)) {
return {
errors: exeContext,
};
}
try {
const eventStream = await executeSubscription(exeContext); // Assert field returned an event stream, otherwise yield an error.
if (!isAsyncIterable(eventStream)) {
throw new Error(
'Subscription field must return Async Iterable. ' +
`Received: ${inspect(eventStream)}.`,
);
}
return eventStream;
} catch (error) {
// If it GraphQLError, report it as an ExecutionResult, containing only errors and no data.
// Otherwise treat the error as a system-class error and re-throw it.
if (error instanceof GraphQLError) {
return {
errors: [error],
};
}
throw error;
}
}
async function executeSubscription(exeContext) {
const { schema, fragments, operation, variableValues, rootValue } =
exeContext;
const rootType = schema.getSubscriptionType();
if (rootType == null) {
throw new GraphQLError(
'Schema is not configured to execute subscription operation.',
{
nodes: operation,
},
);
}
const rootFields = collectFields(
schema,
fragments,
variableValues,
rootType,
operation.selectionSet,
);
const [responseName, fieldNodes] = [...rootFields.entries()][0];
const fieldDef = getFieldDef(schema, rootType, fieldNodes[0]);
if (!fieldDef) {
const fieldName = fieldNodes[0].name.value;
throw new GraphQLError(
`The subscription field "${fieldName}" is not defined.`,
{
nodes: fieldNodes,
},
);
}
const path = addPath(undefined, responseName, rootType.name);
const info = buildResolveInfo(
exeContext,
fieldDef,
fieldNodes,
rootType,
path,
);
try {
var _fieldDef$subscribe;
// Implements the "ResolveFieldEventStream" algorithm from GraphQL specification.
// It differs from "ResolveFieldValue" due to providing a different `resolveFn`.
// Build a JS object of arguments from the field.arguments AST, using the
// variables scope to fulfill any variable references.
const args = getArgumentValues(fieldDef, fieldNodes[0], variableValues); // The resolve function's optional third argument is a context value that
// is provided to every resolve function within an execution. It is commonly
// used to represent an authenticated user, or request-specific caches.
const contextValue = exeContext.contextValue; // Call the `subscribe()` resolver or the default resolver to produce an
// AsyncIterable yielding raw payloads.
const resolveFn =
(_fieldDef$subscribe = fieldDef.subscribe) !== null &&
_fieldDef$subscribe !== void 0
? _fieldDef$subscribe
: exeContext.subscribeFieldResolver;
const eventStream = await resolveFn(rootValue, args, contextValue, info);
if (eventStream instanceof Error) {
throw eventStream;
}
return eventStream;
} catch (error) {
throw locatedError(error, fieldNodes, pathToArray(path));
}
}

View File

@@ -0,0 +1,79 @@
import type { Maybe } from '../jsutils/Maybe';
import type { ObjMap } from '../jsutils/ObjMap';
import { GraphQLError } from '../error/GraphQLError';
import type {
DirectiveNode,
FieldNode,
VariableDefinitionNode,
} from '../language/ast';
import type { GraphQLField } from '../type/definition';
import type { GraphQLDirective } from '../type/directives';
import type { GraphQLSchema } from '../type/schema';
declare type CoercedVariableValues =
| {
errors: ReadonlyArray<GraphQLError>;
coerced?: never;
}
| {
coerced: {
[variable: string]: unknown;
};
errors?: never;
};
/**
* Prepares an object map of variableValues of the correct type based on the
* provided variable definitions and arbitrary input. If the input cannot be
* parsed to match the variable definitions, a GraphQLError will be thrown.
*
* Note: The returned value is a plain Object with a prototype, since it is
* exposed to user code. Care should be taken to not pull values from the
* Object prototype.
*/
export declare function getVariableValues(
schema: GraphQLSchema,
varDefNodes: ReadonlyArray<VariableDefinitionNode>,
inputs: {
readonly [variable: string]: unknown;
},
options?: {
maxErrors?: number;
},
): CoercedVariableValues;
/**
* Prepares an object map of argument values given a list of argument
* definitions and list of argument AST nodes.
*
* Note: The returned value is a plain Object with a prototype, since it is
* exposed to user code. Care should be taken to not pull values from the
* Object prototype.
*/
export declare function getArgumentValues(
def: GraphQLField<unknown, unknown> | GraphQLDirective,
node: FieldNode | DirectiveNode,
variableValues?: Maybe<ObjMap<unknown>>,
): {
[argument: string]: unknown;
};
/**
* Prepares an object map of argument values given a directive definition
* and a AST node which may contain directives. Optionally also accepts a map
* of variable values.
*
* If the directive does not exist on the node, returns undefined.
*
* Note: The returned value is a plain Object with a prototype, since it is
* exposed to user code. Care should be taken to not pull values from the
* Object prototype.
*/
export declare function getDirectiveValues(
directiveDef: GraphQLDirective,
node: {
readonly directives?: ReadonlyArray<DirectiveNode>;
},
variableValues?: Maybe<ObjMap<unknown>>,
):
| undefined
| {
[argument: string]: unknown;
};
export {};

View File

@@ -0,0 +1,300 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.getArgumentValues = getArgumentValues;
exports.getDirectiveValues = getDirectiveValues;
exports.getVariableValues = getVariableValues;
var _inspect = require('../jsutils/inspect.js');
var _keyMap = require('../jsutils/keyMap.js');
var _printPathArray = require('../jsutils/printPathArray.js');
var _GraphQLError = require('../error/GraphQLError.js');
var _kinds = require('../language/kinds.js');
var _printer = require('../language/printer.js');
var _definition = require('../type/definition.js');
var _coerceInputValue = require('../utilities/coerceInputValue.js');
var _typeFromAST = require('../utilities/typeFromAST.js');
var _valueFromAST = require('../utilities/valueFromAST.js');
/**
* Prepares an object map of variableValues of the correct type based on the
* provided variable definitions and arbitrary input. If the input cannot be
* parsed to match the variable definitions, a GraphQLError will be thrown.
*
* Note: The returned value is a plain Object with a prototype, since it is
* exposed to user code. Care should be taken to not pull values from the
* Object prototype.
*/
function getVariableValues(schema, varDefNodes, inputs, options) {
const errors = [];
const maxErrors =
options === null || options === void 0 ? void 0 : options.maxErrors;
try {
const coerced = coerceVariableValues(
schema,
varDefNodes,
inputs,
(error) => {
if (maxErrors != null && errors.length >= maxErrors) {
throw new _GraphQLError.GraphQLError(
'Too many errors processing variables, error limit reached. Execution aborted.',
);
}
errors.push(error);
},
);
if (errors.length === 0) {
return {
coerced,
};
}
} catch (error) {
errors.push(error);
}
return {
errors,
};
}
function coerceVariableValues(schema, varDefNodes, inputs, onError) {
const coercedValues = {};
for (const varDefNode of varDefNodes) {
const varName = varDefNode.variable.name.value;
const varType = (0, _typeFromAST.typeFromAST)(schema, varDefNode.type);
if (!(0, _definition.isInputType)(varType)) {
// Must use input types for variables. This should be caught during
// validation, however is checked again here for safety.
const varTypeStr = (0, _printer.print)(varDefNode.type);
onError(
new _GraphQLError.GraphQLError(
`Variable "$${varName}" expected value of type "${varTypeStr}" which cannot be used as an input type.`,
{
nodes: varDefNode.type,
},
),
);
continue;
}
if (!hasOwnProperty(inputs, varName)) {
if (varDefNode.defaultValue) {
coercedValues[varName] = (0, _valueFromAST.valueFromAST)(
varDefNode.defaultValue,
varType,
);
} else if ((0, _definition.isNonNullType)(varType)) {
const varTypeStr = (0, _inspect.inspect)(varType);
onError(
new _GraphQLError.GraphQLError(
`Variable "$${varName}" of required type "${varTypeStr}" was not provided.`,
{
nodes: varDefNode,
},
),
);
}
continue;
}
const value = inputs[varName];
if (value === null && (0, _definition.isNonNullType)(varType)) {
const varTypeStr = (0, _inspect.inspect)(varType);
onError(
new _GraphQLError.GraphQLError(
`Variable "$${varName}" of non-null type "${varTypeStr}" must not be null.`,
{
nodes: varDefNode,
},
),
);
continue;
}
coercedValues[varName] = (0, _coerceInputValue.coerceInputValue)(
value,
varType,
(path, invalidValue, error) => {
let prefix =
`Variable "$${varName}" got invalid value ` +
(0, _inspect.inspect)(invalidValue);
if (path.length > 0) {
prefix += ` at "${varName}${(0, _printPathArray.printPathArray)(
path,
)}"`;
}
onError(
new _GraphQLError.GraphQLError(prefix + '; ' + error.message, {
nodes: varDefNode,
originalError: error,
}),
);
},
);
}
return coercedValues;
}
/**
* Prepares an object map of argument values given a list of argument
* definitions and list of argument AST nodes.
*
* Note: The returned value is a plain Object with a prototype, since it is
* exposed to user code. Care should be taken to not pull values from the
* Object prototype.
*/
function getArgumentValues(def, node, variableValues) {
var _node$arguments;
const coercedValues = {}; // FIXME: https://github.com/graphql/graphql-js/issues/2203
/* c8 ignore next */
const argumentNodes =
(_node$arguments = node.arguments) !== null && _node$arguments !== void 0
? _node$arguments
: [];
const argNodeMap = (0, _keyMap.keyMap)(
argumentNodes,
(arg) => arg.name.value,
);
for (const argDef of def.args) {
const name = argDef.name;
const argType = argDef.type;
const argumentNode = argNodeMap[name];
if (!argumentNode) {
if (argDef.defaultValue !== undefined) {
coercedValues[name] = argDef.defaultValue;
} else if ((0, _definition.isNonNullType)(argType)) {
throw new _GraphQLError.GraphQLError(
`Argument "${name}" of required type "${(0, _inspect.inspect)(
argType,
)}" ` + 'was not provided.',
{
nodes: node,
},
);
}
continue;
}
const valueNode = argumentNode.value;
let isNull = valueNode.kind === _kinds.Kind.NULL;
if (valueNode.kind === _kinds.Kind.VARIABLE) {
const variableName = valueNode.name.value;
if (
variableValues == null ||
!hasOwnProperty(variableValues, variableName)
) {
if (argDef.defaultValue !== undefined) {
coercedValues[name] = argDef.defaultValue;
} else if ((0, _definition.isNonNullType)(argType)) {
throw new _GraphQLError.GraphQLError(
`Argument "${name}" of required type "${(0, _inspect.inspect)(
argType,
)}" ` +
`was provided the variable "$${variableName}" which was not provided a runtime value.`,
{
nodes: valueNode,
},
);
}
continue;
}
isNull = variableValues[variableName] == null;
}
if (isNull && (0, _definition.isNonNullType)(argType)) {
throw new _GraphQLError.GraphQLError(
`Argument "${name}" of non-null type "${(0, _inspect.inspect)(
argType,
)}" ` + 'must not be null.',
{
nodes: valueNode,
},
);
}
const coercedValue = (0, _valueFromAST.valueFromAST)(
valueNode,
argType,
variableValues,
);
if (coercedValue === undefined) {
// Note: ValuesOfCorrectTypeRule validation should catch this before
// execution. This is a runtime check to ensure execution does not
// continue with an invalid argument value.
throw new _GraphQLError.GraphQLError(
`Argument "${name}" has invalid value ${(0, _printer.print)(
valueNode,
)}.`,
{
nodes: valueNode,
},
);
}
coercedValues[name] = coercedValue;
}
return coercedValues;
}
/**
* Prepares an object map of argument values given a directive definition
* and a AST node which may contain directives. Optionally also accepts a map
* of variable values.
*
* If the directive does not exist on the node, returns undefined.
*
* Note: The returned value is a plain Object with a prototype, since it is
* exposed to user code. Care should be taken to not pull values from the
* Object prototype.
*/
function getDirectiveValues(directiveDef, node, variableValues) {
var _node$directives;
const directiveNode =
(_node$directives = node.directives) === null || _node$directives === void 0
? void 0
: _node$directives.find(
(directive) => directive.name.value === directiveDef.name,
);
if (directiveNode) {
return getArgumentValues(directiveDef, directiveNode, variableValues);
}
}
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}

View File

@@ -0,0 +1,263 @@
import { inspect } from '../jsutils/inspect.mjs';
import { keyMap } from '../jsutils/keyMap.mjs';
import { printPathArray } from '../jsutils/printPathArray.mjs';
import { GraphQLError } from '../error/GraphQLError.mjs';
import { Kind } from '../language/kinds.mjs';
import { print } from '../language/printer.mjs';
import { isInputType, isNonNullType } from '../type/definition.mjs';
import { coerceInputValue } from '../utilities/coerceInputValue.mjs';
import { typeFromAST } from '../utilities/typeFromAST.mjs';
import { valueFromAST } from '../utilities/valueFromAST.mjs';
/**
* Prepares an object map of variableValues of the correct type based on the
* provided variable definitions and arbitrary input. If the input cannot be
* parsed to match the variable definitions, a GraphQLError will be thrown.
*
* Note: The returned value is a plain Object with a prototype, since it is
* exposed to user code. Care should be taken to not pull values from the
* Object prototype.
*/
export function getVariableValues(schema, varDefNodes, inputs, options) {
const errors = [];
const maxErrors =
options === null || options === void 0 ? void 0 : options.maxErrors;
try {
const coerced = coerceVariableValues(
schema,
varDefNodes,
inputs,
(error) => {
if (maxErrors != null && errors.length >= maxErrors) {
throw new GraphQLError(
'Too many errors processing variables, error limit reached. Execution aborted.',
);
}
errors.push(error);
},
);
if (errors.length === 0) {
return {
coerced,
};
}
} catch (error) {
errors.push(error);
}
return {
errors,
};
}
function coerceVariableValues(schema, varDefNodes, inputs, onError) {
const coercedValues = {};
for (const varDefNode of varDefNodes) {
const varName = varDefNode.variable.name.value;
const varType = typeFromAST(schema, varDefNode.type);
if (!isInputType(varType)) {
// Must use input types for variables. This should be caught during
// validation, however is checked again here for safety.
const varTypeStr = print(varDefNode.type);
onError(
new GraphQLError(
`Variable "$${varName}" expected value of type "${varTypeStr}" which cannot be used as an input type.`,
{
nodes: varDefNode.type,
},
),
);
continue;
}
if (!hasOwnProperty(inputs, varName)) {
if (varDefNode.defaultValue) {
coercedValues[varName] = valueFromAST(varDefNode.defaultValue, varType);
} else if (isNonNullType(varType)) {
const varTypeStr = inspect(varType);
onError(
new GraphQLError(
`Variable "$${varName}" of required type "${varTypeStr}" was not provided.`,
{
nodes: varDefNode,
},
),
);
}
continue;
}
const value = inputs[varName];
if (value === null && isNonNullType(varType)) {
const varTypeStr = inspect(varType);
onError(
new GraphQLError(
`Variable "$${varName}" of non-null type "${varTypeStr}" must not be null.`,
{
nodes: varDefNode,
},
),
);
continue;
}
coercedValues[varName] = coerceInputValue(
value,
varType,
(path, invalidValue, error) => {
let prefix =
`Variable "$${varName}" got invalid value ` + inspect(invalidValue);
if (path.length > 0) {
prefix += ` at "${varName}${printPathArray(path)}"`;
}
onError(
new GraphQLError(prefix + '; ' + error.message, {
nodes: varDefNode,
originalError: error,
}),
);
},
);
}
return coercedValues;
}
/**
* Prepares an object map of argument values given a list of argument
* definitions and list of argument AST nodes.
*
* Note: The returned value is a plain Object with a prototype, since it is
* exposed to user code. Care should be taken to not pull values from the
* Object prototype.
*/
export function getArgumentValues(def, node, variableValues) {
var _node$arguments;
const coercedValues = {}; // FIXME: https://github.com/graphql/graphql-js/issues/2203
/* c8 ignore next */
const argumentNodes =
(_node$arguments = node.arguments) !== null && _node$arguments !== void 0
? _node$arguments
: [];
const argNodeMap = keyMap(argumentNodes, (arg) => arg.name.value);
for (const argDef of def.args) {
const name = argDef.name;
const argType = argDef.type;
const argumentNode = argNodeMap[name];
if (!argumentNode) {
if (argDef.defaultValue !== undefined) {
coercedValues[name] = argDef.defaultValue;
} else if (isNonNullType(argType)) {
throw new GraphQLError(
`Argument "${name}" of required type "${inspect(argType)}" ` +
'was not provided.',
{
nodes: node,
},
);
}
continue;
}
const valueNode = argumentNode.value;
let isNull = valueNode.kind === Kind.NULL;
if (valueNode.kind === Kind.VARIABLE) {
const variableName = valueNode.name.value;
if (
variableValues == null ||
!hasOwnProperty(variableValues, variableName)
) {
if (argDef.defaultValue !== undefined) {
coercedValues[name] = argDef.defaultValue;
} else if (isNonNullType(argType)) {
throw new GraphQLError(
`Argument "${name}" of required type "${inspect(argType)}" ` +
`was provided the variable "$${variableName}" which was not provided a runtime value.`,
{
nodes: valueNode,
},
);
}
continue;
}
isNull = variableValues[variableName] == null;
}
if (isNull && isNonNullType(argType)) {
throw new GraphQLError(
`Argument "${name}" of non-null type "${inspect(argType)}" ` +
'must not be null.',
{
nodes: valueNode,
},
);
}
const coercedValue = valueFromAST(valueNode, argType, variableValues);
if (coercedValue === undefined) {
// Note: ValuesOfCorrectTypeRule validation should catch this before
// execution. This is a runtime check to ensure execution does not
// continue with an invalid argument value.
throw new GraphQLError(
`Argument "${name}" has invalid value ${print(valueNode)}.`,
{
nodes: valueNode,
},
);
}
coercedValues[name] = coercedValue;
}
return coercedValues;
}
/**
* Prepares an object map of argument values given a directive definition
* and a AST node which may contain directives. Optionally also accepts a map
* of variable values.
*
* If the directive does not exist on the node, returns undefined.
*
* Note: The returned value is a plain Object with a prototype, since it is
* exposed to user code. Care should be taken to not pull values from the
* Object prototype.
*/
export function getDirectiveValues(directiveDef, node, variableValues) {
var _node$directives;
const directiveNode =
(_node$directives = node.directives) === null || _node$directives === void 0
? void 0
: _node$directives.find(
(directive) => directive.name.value === directiveDef.name,
);
if (directiveNode) {
return getArgumentValues(directiveDef, directiveNode, variableValues);
}
}
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}