Skip to content

Commit

Permalink
GraphQLError: convert to ES6 class (#2369)
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanGoncharov authored Jan 20, 2020
1 parent 1d85e45 commit a9bf2f5
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 140 deletions.
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

0 comments on commit a9bf2f5

Please sign in to comment.