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.
254 lines
7.0 KiB
254 lines
7.0 KiB
5 months ago
|
import { isObjectLike } from '../jsutils/isObjectLike.mjs';
|
||
|
import { getLocation } from '../language/location.mjs';
|
||
|
import {
|
||
|
printLocation,
|
||
|
printSourceLocation,
|
||
|
} from '../language/printLocation.mjs';
|
||
|
|
||
|
function toNormalizedOptions(args) {
|
||
|
const firstArg = args[0];
|
||
|
|
||
|
if (firstArg == null || 'kind' in firstArg || 'length' in firstArg) {
|
||
|
return {
|
||
|
nodes: firstArg,
|
||
|
source: args[1],
|
||
|
positions: args[2],
|
||
|
path: args[3],
|
||
|
originalError: args[4],
|
||
|
extensions: args[5],
|
||
|
};
|
||
|
}
|
||
|
|
||
|
return firstArg;
|
||
|
}
|
||
|
/**
|
||
|
* A GraphQLError describes an Error found during the parse, validate, or
|
||
|
* execute phases of performing a GraphQL operation. In addition to a message
|
||
|
* and stack trace, it also includes information about the locations in a
|
||
|
* GraphQL document and/or execution result that correspond to the Error.
|
||
|
*/
|
||
|
|
||
|
export class GraphQLError extends Error {
|
||
|
/**
|
||
|
* An array of `{ line, column }` locations within the source GraphQL document
|
||
|
* which correspond to this error.
|
||
|
*
|
||
|
* Errors during validation often contain multiple locations, for example to
|
||
|
* point out two things with the same name. Errors during execution include a
|
||
|
* single location, the field which produced the error.
|
||
|
*
|
||
|
* Enumerable, and appears in the result of JSON.stringify().
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* An array describing the JSON-path into the execution response which
|
||
|
* corresponds to this error. Only included for errors during execution.
|
||
|
*
|
||
|
* Enumerable, and appears in the result of JSON.stringify().
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* An array of GraphQL AST Nodes corresponding to this error.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* The source GraphQL document for the first location of this error.
|
||
|
*
|
||
|
* Note that if this Error represents more than one node, the source may not
|
||
|
* represent nodes after the first node.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* An array of character offsets within the source GraphQL document
|
||
|
* which correspond to this error.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* The original error thrown from a field resolver during execution.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Extension fields to add to the formatted error.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @deprecated Please use the `GraphQLErrorOptions` constructor overload instead.
|
||
|
*/
|
||
|
constructor(message, ...rawArgs) {
|
||
|
var _this$nodes, _nodeLocations$, _ref;
|
||
|
|
||
|
const { nodes, source, positions, path, originalError, extensions } =
|
||
|
toNormalizedOptions(rawArgs);
|
||
|
super(message);
|
||
|
this.name = 'GraphQLError';
|
||
|
this.path = path !== null && path !== void 0 ? path : undefined;
|
||
|
this.originalError =
|
||
|
originalError !== null && originalError !== void 0
|
||
|
? originalError
|
||
|
: undefined; // Compute list of blame nodes.
|
||
|
|
||
|
this.nodes = undefinedIfEmpty(
|
||
|
Array.isArray(nodes) ? nodes : nodes ? [nodes] : undefined,
|
||
|
);
|
||
|
const nodeLocations = undefinedIfEmpty(
|
||
|
(_this$nodes = this.nodes) === null || _this$nodes === void 0
|
||
|
? void 0
|
||
|
: _this$nodes.map((node) => node.loc).filter((loc) => loc != null),
|
||
|
); // Compute locations in the source for the given nodes/positions.
|
||
|
|
||
|
this.source =
|
||
|
source !== null && source !== void 0
|
||
|
? source
|
||
|
: nodeLocations === null || nodeLocations === void 0
|
||
|
? void 0
|
||
|
: (_nodeLocations$ = nodeLocations[0]) === null ||
|
||
|
_nodeLocations$ === void 0
|
||
|
? void 0
|
||
|
: _nodeLocations$.source;
|
||
|
this.positions =
|
||
|
positions !== null && positions !== void 0
|
||
|
? positions
|
||
|
: nodeLocations === null || nodeLocations === void 0
|
||
|
? void 0
|
||
|
: nodeLocations.map((loc) => loc.start);
|
||
|
this.locations =
|
||
|
positions && source
|
||
|
? positions.map((pos) => getLocation(source, pos))
|
||
|
: nodeLocations === null || nodeLocations === void 0
|
||
|
? void 0
|
||
|
: nodeLocations.map((loc) => getLocation(loc.source, loc.start));
|
||
|
const originalExtensions = isObjectLike(
|
||
|
originalError === null || originalError === void 0
|
||
|
? void 0
|
||
|
: originalError.extensions,
|
||
|
)
|
||
|
? originalError === null || originalError === void 0
|
||
|
? void 0
|
||
|
: originalError.extensions
|
||
|
: undefined;
|
||
|
this.extensions =
|
||
|
(_ref =
|
||
|
extensions !== null && extensions !== void 0
|
||
|
? extensions
|
||
|
: originalExtensions) !== null && _ref !== void 0
|
||
|
? _ref
|
||
|
: Object.create(null); // Only properties prescribed by the spec should be enumerable.
|
||
|
// Keep the rest as non-enumerable.
|
||
|
|
||
|
Object.defineProperties(this, {
|
||
|
message: {
|
||
|
writable: true,
|
||
|
enumerable: true,
|
||
|
},
|
||
|
name: {
|
||
|
enumerable: false,
|
||
|
},
|
||
|
nodes: {
|
||
|
enumerable: false,
|
||
|
},
|
||
|
source: {
|
||
|
enumerable: false,
|
||
|
},
|
||
|
positions: {
|
||
|
enumerable: false,
|
||
|
},
|
||
|
originalError: {
|
||
|
enumerable: false,
|
||
|
},
|
||
|
}); // Include (non-enumerable) stack trace.
|
||
|
|
||
|
/* c8 ignore start */
|
||
|
// FIXME: https://github.com/graphql/graphql-js/issues/2317
|
||
|
|
||
|
if (
|
||
|
originalError !== null &&
|
||
|
originalError !== void 0 &&
|
||
|
originalError.stack
|
||
|
) {
|
||
|
Object.defineProperty(this, 'stack', {
|
||
|
value: originalError.stack,
|
||
|
writable: true,
|
||
|
configurable: true,
|
||
|
});
|
||
|
} else if (Error.captureStackTrace) {
|
||
|
Error.captureStackTrace(this, GraphQLError);
|
||
|
} else {
|
||
|
Object.defineProperty(this, 'stack', {
|
||
|
value: Error().stack,
|
||
|
writable: true,
|
||
|
configurable: true,
|
||
|
});
|
||
|
}
|
||
|
/* c8 ignore stop */
|
||
|
}
|
||
|
|
||
|
get [Symbol.toStringTag]() {
|
||
|
return 'GraphQLError';
|
||
|
}
|
||
|
|
||
|
toString() {
|
||
|
let output = this.message;
|
||
|
|
||
|
if (this.nodes) {
|
||
|
for (const node of this.nodes) {
|
||
|
if (node.loc) {
|
||
|
output += '\n\n' + printLocation(node.loc);
|
||
|
}
|
||
|
}
|
||
|
} else if (this.source && this.locations) {
|
||
|
for (const location of this.locations) {
|
||
|
output += '\n\n' + printSourceLocation(this.source, location);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return output;
|
||
|
}
|
||
|
|
||
|
toJSON() {
|
||
|
const formattedError = {
|
||
|
message: this.message,
|
||
|
};
|
||
|
|
||
|
if (this.locations != null) {
|
||
|
formattedError.locations = this.locations;
|
||
|
}
|
||
|
|
||
|
if (this.path != null) {
|
||
|
formattedError.path = this.path;
|
||
|
}
|
||
|
|
||
|
if (this.extensions != null && Object.keys(this.extensions).length > 0) {
|
||
|
formattedError.extensions = this.extensions;
|
||
|
}
|
||
|
|
||
|
return formattedError;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function undefinedIfEmpty(array) {
|
||
|
return array === undefined || array.length === 0 ? undefined : array;
|
||
|
}
|
||
|
/**
|
||
|
* See: https://spec.graphql.org/draft/#sec-Errors
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Prints a GraphQLError to a string, representing useful location information
|
||
|
* about the error's position in the source.
|
||
|
*
|
||
|
* @deprecated Please use `error.toString` instead. Will be removed in v17
|
||
|
*/
|
||
|
export function printError(error) {
|
||
|
return error.toString();
|
||
|
}
|
||
|
/**
|
||
|
* Given a GraphQLError, format it according to the rules described by the
|
||
|
* Response Format, Errors section of the GraphQL Specification.
|
||
|
*
|
||
|
* @deprecated Please use `error.toJSON` instead. Will be removed in v17
|
||
|
*/
|
||
|
|
||
|
export function formatError(error) {
|
||
|
return error.toJSON();
|
||
|
}
|