mirror of
https://github.com/JamesIves/github-pages-deploy-action.git
synced 2023-12-15 20:03:39 +08:00
243 lines
7.3 KiB
Plaintext
243 lines
7.3 KiB
Plaintext
|
// @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';
|
||
|
import { type SourceLocation, getLocation } from '../language/location';
|
||
|
import { printLocation, printSourceLocation } from '../language/printLocation';
|
||
|
|
||
|
/**
|
||
|
* 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 {
|
||
|
/**
|
||
|
* A message describing the Error for debugging purposes.
|
||
|
*
|
||
|
* Enumerable, and appears in the result of JSON.stringify().
|
||
|
*
|
||
|
* Note: should be treated as readonly, despite invariant usage.
|
||
|
*/
|
||
|
message: string;
|
||
|
|
||
|
/**
|
||
|
* 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().
|
||
|
*/
|
||
|
+locations: $ReadOnlyArray<SourceLocation> | void;
|
||
|
|
||
|
/**
|
||
|
* 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().
|
||
|
*/
|
||
|
+path: $ReadOnlyArray<string | number> | void;
|
||
|
|
||
|
/**
|
||
|
* An array of GraphQL AST Nodes corresponding to this error.
|
||
|
*/
|
||
|
+nodes: $ReadOnlyArray<ASTNode> | void;
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*/
|
||
|
+source: Source | void;
|
||
|
|
||
|
/**
|
||
|
* An array of character offsets within the source GraphQL document
|
||
|
* which correspond to this error.
|
||
|
*/
|
||
|
+positions: $ReadOnlyArray<number> | void;
|
||
|
|
||
|
/**
|
||
|
* The original error thrown from a field resolver during execution.
|
||
|
*/
|
||
|
+originalError: ?Error;
|
||
|
|
||
|
/**
|
||
|
* Extension fields to add to the formatted error.
|
||
|
*/
|
||
|
+extensions: { [key: string]: mixed, ... } | void;
|
||
|
|
||
|
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) {
|
||
|
_source = _nodes[0].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 _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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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?.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,
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
toString(): string {
|
||
|
return printError(this);
|
||
|
}
|
||
|
|
||
|
// 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';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Prints a GraphQLError to a string, representing useful location information
|
||
|
* about the error's position in the source.
|
||
|
*/
|
||
|
export function printError(error: GraphQLError): string {
|
||
|
let output = error.message;
|
||
|
|
||
|
if (error.nodes) {
|
||
|
for (const node of error.nodes) {
|
||
|
if (node.loc) {
|
||
|
output += '\n\n' + printLocation(node.loc);
|
||
|
}
|
||
|
}
|
||
|
} else if (error.source && error.locations) {
|
||
|
for (const location of error.locations) {
|
||
|
output += '\n\n' + printSourceLocation(error.source, location);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return output;
|
||
|
}
|