Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GraphQLError: convert to ES6 class #2369

Merged
merged 1 commit into from
Jan 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
"presets": [["@babel/preset-env", { "modules": false }]]
}
}
},
{
"include": "src/error/GraphQLError.js",
"plugins": [
["@babel/plugin-transform-classes", { "loose": false }]
]
}
]
}
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"jsutils",
"tsutils",
"noflow",
"flowlint",

// Different names used inside tests
"Skywalker",
Expand Down
277 changes: 137 additions & 140 deletions src/error/GraphQLError.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// @flow strict

// FIXME:
// flowlint uninitialized-instance-property:off

import isObjectLike from '../jsutils/isObjectLike';
import { SYMBOL_TO_STRING_TAG } from '../polyfills/symbols';

import { type ASTNode } from '../language/ast';
import { type Source } from '../language/source';
Expand All @@ -13,17 +17,7 @@ import { printLocation, printSourceLocation } from '../language/printLocation';
* and stack trace, it also includes information about the locations in a
* GraphQL document and/or execution result that correspond to the Error.
*/
declare class GraphQLError extends Error {
constructor(
message: string,
nodes?: $ReadOnlyArray<ASTNode> | ASTNode | void | null,
source?: ?Source,
positions?: ?$ReadOnlyArray<number>,
path?: ?$ReadOnlyArray<string | number>,
originalError?: ?Error,
extensions?: ?{ [key: string]: mixed, ... },
): void;

export class GraphQLError extends Error {
/**
* A message describing the Error for debugging purposes.
*
Expand Down Expand Up @@ -81,148 +75,151 @@ declare class GraphQLError extends Error {
* Extension fields to add to the formatted error.
*/
+extensions: { [key: string]: mixed, ... } | void;
}

export function GraphQLError( // eslint-disable-line no-redeclare
message: string,
nodes?: $ReadOnlyArray<ASTNode> | ASTNode | void,
source?: ?Source,
positions?: ?$ReadOnlyArray<number>,
path?: ?$ReadOnlyArray<string | number>,
originalError?: ?Error & { +extensions: mixed, ... },
extensions?: ?{ [key: string]: mixed, ... },
) {
// Compute list of blame nodes.
const _nodes = Array.isArray(nodes)
? nodes.length !== 0
? nodes
: undefined
: nodes
? [nodes]
: undefined;

// Compute locations in the source for the given nodes/positions.
let _source = source;
if (!_source && _nodes) {
const node = _nodes[0];
_source = node && node.loc && node.loc.source;
}
constructor(
message: string,
nodes?: $ReadOnlyArray<ASTNode> | ASTNode | void | null,
source?: ?Source,
positions?: ?$ReadOnlyArray<number>,
path?: ?$ReadOnlyArray<string | number>,
originalError?: ?(Error & { +extensions?: mixed, ... }),
extensions?: ?{ [key: string]: mixed, ... },
): void {
super(message);

// Compute list of blame nodes.
const _nodes = Array.isArray(nodes)
? nodes.length !== 0
? nodes
: undefined
: nodes
? [nodes]
: undefined;

// Compute locations in the source for the given nodes/positions.
let _source = source;
if (!_source && _nodes) {
const node = _nodes[0];
_source = node && node.loc && node.loc.source;
}

let _positions = positions;
if (!_positions && _nodes) {
_positions = _nodes.reduce((list, node) => {
if (node.loc) {
list.push(node.loc.start);
}
return list;
}, []);
}
if (_positions && _positions.length === 0) {
_positions = undefined;
}
let _positions = positions;
if (!_positions && _nodes) {
_positions = _nodes.reduce((list, node) => {
if (node.loc) {
list.push(node.loc.start);
}
return list;
}, []);
}
if (_positions && _positions.length === 0) {
_positions = undefined;
}

let _locations;
if (positions && source) {
_locations = positions.map(pos => getLocation(source, pos));
} else if (_nodes) {
_locations = _nodes.reduce((list, node) => {
if (node.loc) {
list.push(getLocation(node.loc.source, node.loc.start));
let _locations;
if (positions && source) {
_locations = positions.map(pos => getLocation(source, pos));
} else if (_nodes) {
_locations = _nodes.reduce((list, node) => {
if (node.loc) {
list.push(getLocation(node.loc.source, node.loc.start));
}
return list;
}, []);
}

let _extensions = extensions;
if (_extensions == null && originalError != null) {
const originalExtensions = originalError.extensions;
if (isObjectLike(originalExtensions)) {
_extensions = originalExtensions;
}
return list;
}, []);
}
}

let _extensions = extensions;
if (_extensions == null && originalError != null) {
const originalExtensions = originalError.extensions;
if (isObjectLike(originalExtensions)) {
_extensions = originalExtensions;
Object.defineProperties((this: any), {
name: { value: 'GraphQLError' },
message: {
value: message,
// By being enumerable, JSON.stringify will include `message` in the
// resulting output. This ensures that the simplest possible GraphQL
// service adheres to the spec.
enumerable: true,
writable: true,
},
locations: {
// Coercing falsy values to undefined ensures they will not be included
// in JSON.stringify() when not provided.
value: _locations || undefined,
// By being enumerable, JSON.stringify will include `locations` in the
// resulting output. This ensures that the simplest possible GraphQL
// service adheres to the spec.
enumerable: _locations != null,
},
path: {
// Coercing falsy values to undefined ensures they will not be included
// in JSON.stringify() when not provided.
value: path || undefined,
// By being enumerable, JSON.stringify will include `path` in the
// resulting output. This ensures that the simplest possible GraphQL
// service adheres to the spec.
enumerable: path != null,
},
nodes: {
value: _nodes || undefined,
},
source: {
value: _source || undefined,
},
positions: {
value: _positions || undefined,
},
originalError: {
value: originalError,
},
extensions: {
// Coercing falsy values to undefined ensures they will not be included
// in JSON.stringify() when not provided.
value: _extensions || undefined,
// By being enumerable, JSON.stringify will include `path` in the
// resulting output. This ensures that the simplest possible GraphQL
// service adheres to the spec.
enumerable: _extensions != null,
},
});

// Include (non-enumerable) stack trace.
if (originalError && originalError.stack) {
Object.defineProperty(this, 'stack', {
value: originalError.stack,
writable: true,
configurable: true,
});
return;
}

/* istanbul ignore next (See: https://github.com/graphql/graphql-js/issues/2317) */
if (Error.captureStackTrace) {
Error.captureStackTrace(this, GraphQLError);
} else {
Object.defineProperty(this, 'stack', {
value: Error().stack,
writable: true,
configurable: true,
});
}
}

Object.defineProperties(this, {
message: {
value: message,
// By being enumerable, JSON.stringify will include `message` in the
// resulting output. This ensures that the simplest possible GraphQL
// service adheres to the spec.
enumerable: true,
writable: true,
},
locations: {
// Coercing falsy values to undefined ensures they will not be included
// in JSON.stringify() when not provided.
value: _locations || undefined,
// By being enumerable, JSON.stringify will include `locations` in the
// resulting output. This ensures that the simplest possible GraphQL
// service adheres to the spec.
enumerable: _locations != null,
},
path: {
// Coercing falsy values to undefined ensures they will not be included
// in JSON.stringify() when not provided.
value: path || undefined,
// By being enumerable, JSON.stringify will include `path` in the
// resulting output. This ensures that the simplest possible GraphQL
// service adheres to the spec.
enumerable: path != null,
},
nodes: {
value: _nodes || undefined,
},
source: {
value: _source || undefined,
},
positions: {
value: _positions || undefined,
},
originalError: {
value: originalError,
},
extensions: {
// Coercing falsy values to undefined ensures they will not be included
// in JSON.stringify() when not provided.
value: _extensions || undefined,
// By being enumerable, JSON.stringify will include `path` in the
// resulting output. This ensures that the simplest possible GraphQL
// service adheres to the spec.
enumerable: _extensions != null,
},
});

// Include (non-enumerable) stack trace.
if (originalError && originalError.stack) {
Object.defineProperty(this, 'stack', {
value: originalError.stack,
writable: true,
configurable: true,
});
return;
toString(): string {
return printError(this);
}

/* istanbul ignore next (See: https://github.com/graphql/graphql-js/issues/2317) */
if (Error.captureStackTrace) {
Error.captureStackTrace(this, GraphQLError);
} else {
Object.defineProperty(this, 'stack', {
value: Error().stack,
writable: true,
configurable: true,
});
// FIXME: workaround to not break chai comparisons, should be remove in v16
// $FlowFixMe Flow doesn't support computed properties yet
get [SYMBOL_TO_STRING_TAG](): string {
return 'Object';
}
}

(GraphQLError: any).prototype = Object.create(Error.prototype, {
constructor: { value: GraphQLError },
name: { value: 'GraphQLError' },
toString: {
value: function toString() {
return printError(this);
},
},
});

/**
* Prints a GraphQLError to a string, representing useful location information
* about the error's position in the source.
Expand Down