Skip to content

Commit

Permalink
feat: replace instanceOf with unique Symbol checks
Browse files Browse the repository at this point in the history
  • Loading branch information
n1ru4l committed Jun 3, 2022
1 parent 540bb38 commit b71648f
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 21 deletions.
9 changes: 9 additions & 0 deletions src/error/GraphQLError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,22 @@ export interface GraphQLErrorOptions {
extensions?: Maybe<GraphQLErrorExtensions>;
}

const isGraphQLErrorSymbol = Symbol.for('GraphQLError');

export function isGraphQLError(error: unknown): error is GraphQLError {
return (
typeof error === 'object' && error != null && isGraphQLErrorSymbol in error
);
}

/**
* 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 {
[isGraphQLErrorSymbol]: true = true;
/**
* An array of `{ line, column }` locations within the source GraphQL document
* which correspond to this error.
Expand Down
4 changes: 2 additions & 2 deletions src/execution/subscribe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { isAsyncIterable } from '../jsutils/isAsyncIterable';
import type { Maybe } from '../jsutils/Maybe';
import { addPath, pathToArray } from '../jsutils/Path';

import { GraphQLError } from '../error/GraphQLError';
import { GraphQLError, isGraphQLError } from '../error/GraphQLError';
import { locatedError } from '../error/locatedError';

import type { DocumentNode } from '../language/ast';
Expand Down Expand Up @@ -169,7 +169,7 @@ export async function createSourceEventStream(
} 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) {
if (isGraphQLError(error)) {
return { errors: [error] };
}
throw error;
Expand Down
8 changes: 6 additions & 2 deletions src/language/source.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { devAssert } from '../jsutils/devAssert';
import { inspect } from '../jsutils/inspect';
import { instanceOf } from '../jsutils/instanceOf';

interface Location {
line: number;
column: number;
}

const isSourceSymbol = Symbol.for('Source');

/**
* A representation of source input to GraphQL. The `name` and `locationOffset` parameters are
* optional, but they are useful for clients who store GraphQL documents in source files.
Expand All @@ -15,6 +16,7 @@ interface Location {
* The `line` and `column` properties in `locationOffset` are 1-indexed.
*/
export class Source {
[isSourceSymbol]: true = true;
body: string;
name: string;
locationOffset: Location;
Expand Down Expand Up @@ -53,5 +55,7 @@ export class Source {
* @internal
*/
export function isSource(source: unknown): source is Source {
return instanceOf(source, Source);
return (
typeof source === 'object' && source != null && isSourceSymbol in source
);
}
67 changes: 58 additions & 9 deletions src/type/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { devAssert } from '../jsutils/devAssert';
import { didYouMean } from '../jsutils/didYouMean';
import { identityFunc } from '../jsutils/identityFunc';
import { inspect } from '../jsutils/inspect';
import { instanceOf } from '../jsutils/instanceOf';
import { isObjectLike } from '../jsutils/isObjectLike';
import { keyMap } from '../jsutils/keyMap';
import { keyValMap } from '../jsutils/keyValMap';
Expand Down Expand Up @@ -75,11 +74,17 @@ export function assertType(type: unknown): GraphQLType {
return type;
}

const isGraphQLScalarTypeSymbol = Symbol.for('GraphQLScalarType');

/**
* There are predicates for each kind of GraphQL type.
*/
export function isScalarType(type: unknown): type is GraphQLScalarType {
return instanceOf(type, GraphQLScalarType);
return (
typeof type === 'object' &&
type != null &&
isGraphQLScalarTypeSymbol in type
);
}

export function assertScalarType(type: unknown): GraphQLScalarType {
Expand All @@ -89,8 +94,14 @@ export function assertScalarType(type: unknown): GraphQLScalarType {
return type;
}

const isGraphQLObjectTypeSymbol = Symbol.for('GraphQLObjectType');

export function isObjectType(type: unknown): type is GraphQLObjectType {
return instanceOf(type, GraphQLObjectType);
return (
typeof type === 'object' &&
type != null &&
isGraphQLObjectTypeSymbol in type
);
}

export function assertObjectType(type: unknown): GraphQLObjectType {
Expand All @@ -100,8 +111,14 @@ export function assertObjectType(type: unknown): GraphQLObjectType {
return type;
}

const isGraphQLInterfaceTypeSymbol = Symbol.for('GraphQLInterfaceType');

export function isInterfaceType(type: unknown): type is GraphQLInterfaceType {
return instanceOf(type, GraphQLInterfaceType);
return (
typeof type === 'object' &&
type != null &&
isGraphQLInterfaceTypeSymbol in type
);
}

export function assertInterfaceType(type: unknown): GraphQLInterfaceType {
Expand All @@ -113,8 +130,12 @@ export function assertInterfaceType(type: unknown): GraphQLInterfaceType {
return type;
}

const isGraphQLUnionTypeSymbol = Symbol.for('GraphQLUnionType');

export function isUnionType(type: unknown): type is GraphQLUnionType {
return instanceOf(type, GraphQLUnionType);
return (
typeof type === 'object' && type != null && isGraphQLUnionTypeSymbol in type
);
}

export function assertUnionType(type: unknown): GraphQLUnionType {
Expand All @@ -124,8 +145,12 @@ export function assertUnionType(type: unknown): GraphQLUnionType {
return type;
}

const isGraphQLEnumTypeSymbol = Symbol.for('GraphQLEnumType');

export function isEnumType(type: unknown): type is GraphQLEnumType {
return instanceOf(type, GraphQLEnumType);
return (
typeof type === 'object' && type != null && isGraphQLEnumTypeSymbol in type
);
}

export function assertEnumType(type: unknown): GraphQLEnumType {
Expand All @@ -135,10 +160,16 @@ export function assertEnumType(type: unknown): GraphQLEnumType {
return type;
}

const isGraphQLInputObjectTypeSymbol = Symbol.for('GraphQLInputObjectType');

export function isInputObjectType(
type: unknown,
): type is GraphQLInputObjectType {
return instanceOf(type, GraphQLInputObjectType);
return (
typeof type === 'object' &&
type != null &&
isGraphQLInputObjectTypeSymbol in type
);
}

export function assertInputObjectType(type: unknown): GraphQLInputObjectType {
Expand All @@ -150,6 +181,8 @@ export function assertInputObjectType(type: unknown): GraphQLInputObjectType {
return type;
}

const isGraphQLListTypeSymbol = Symbol.for('GraphQLListType');

export function isListType(
type: GraphQLInputType,
): type is GraphQLList<GraphQLInputType>;
Expand All @@ -158,7 +191,9 @@ export function isListType(
): type is GraphQLList<GraphQLOutputType>;
export function isListType(type: unknown): type is GraphQLList<GraphQLType>;
export function isListType(type: unknown): type is GraphQLList<GraphQLType> {
return instanceOf(type, GraphQLList);
return (
typeof type === 'object' && type != null && isGraphQLListTypeSymbol in type
);
}

export function assertListType(type: unknown): GraphQLList<GraphQLType> {
Expand All @@ -168,6 +203,8 @@ export function assertListType(type: unknown): GraphQLList<GraphQLType> {
return type;
}

const isGraphQLNonNullTypeSymbol = Symbol.for('GraphQLNonNullType');

export function isNonNullType(
type: GraphQLInputType,
): type is GraphQLNonNull<GraphQLNullableInputType>;
Expand All @@ -180,7 +217,11 @@ export function isNonNullType(
export function isNonNullType(
type: unknown,
): type is GraphQLNonNull<GraphQLNullableType> {
return instanceOf(type, GraphQLNonNull);
return (
typeof type === 'object' &&
type != null &&
isGraphQLNonNullTypeSymbol in type
);
}

export function assertNonNullType(type: unknown): GraphQLNonNull<GraphQLType> {
Expand Down Expand Up @@ -319,6 +360,7 @@ export function assertAbstractType(type: unknown): GraphQLAbstractType {
* ```
*/
export class GraphQLList<T extends GraphQLType> {
readonly [isGraphQLListTypeSymbol]: true = true;
readonly ofType: T;

constructor(ofType: T) {
Expand Down Expand Up @@ -365,6 +407,7 @@ export class GraphQLList<T extends GraphQLType> {
* Note: the enforcement of non-nullability occurs within the executor.
*/
export class GraphQLNonNull<T extends GraphQLNullableType> {
readonly [isGraphQLNonNullTypeSymbol]: true = true;
readonly ofType: T;

constructor(ofType: T) {
Expand Down Expand Up @@ -555,6 +598,7 @@ export interface GraphQLScalarTypeExtensions {
* ```
*/
export class GraphQLScalarType<TInternal = unknown, TExternal = TInternal> {
readonly [isGraphQLScalarTypeSymbol]: true = true;
name: string;
description: Maybe<string>;
specifiedByURL: Maybe<string>;
Expand Down Expand Up @@ -725,6 +769,7 @@ export interface GraphQLObjectTypeExtensions<_TSource = any, _TContext = any> {
* ```
*/
export class GraphQLObjectType<TSource = any, TContext = any> {
readonly [isGraphQLObjectTypeSymbol]: true = true;
name: string;
description: Maybe<string>;
isTypeOf: Maybe<GraphQLIsTypeOfFn<TSource, TContext>>;
Expand Down Expand Up @@ -1078,6 +1123,7 @@ export interface GraphQLInterfaceTypeExtensions {
* ```
*/
export class GraphQLInterfaceType {
readonly [isGraphQLInterfaceTypeSymbol]: true = true;
name: string;
description: Maybe<string>;
resolveType: Maybe<GraphQLTypeResolver<any, any>>;
Expand Down Expand Up @@ -1207,6 +1253,7 @@ export interface GraphQLUnionTypeExtensions {
* ```
*/
export class GraphQLUnionType {
readonly [isGraphQLUnionTypeSymbol]: true = true;
name: string;
description: Maybe<string>;
resolveType: Maybe<GraphQLTypeResolver<any, any>>;
Expand Down Expand Up @@ -1334,6 +1381,7 @@ export interface GraphQLEnumTypeExtensions {
* will be used as its internal value.
*/
export class GraphQLEnumType /* <T> */ {
readonly [isGraphQLEnumTypeSymbol]: true = true;
name: string;
description: Maybe<string>;
extensions: Readonly<GraphQLEnumTypeExtensions>;
Expand Down Expand Up @@ -1574,6 +1622,7 @@ export interface GraphQLInputObjectTypeExtensions {
* ```
*/
export class GraphQLInputObjectType {
readonly [isGraphQLInputObjectTypeSymbol]: true = true;
name: string;
description: Maybe<string>;
extensions: Readonly<GraphQLInputObjectTypeExtensions>;
Expand Down
10 changes: 8 additions & 2 deletions src/type/directives.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { devAssert } from '../jsutils/devAssert';
import { inspect } from '../jsutils/inspect';
import { instanceOf } from '../jsutils/instanceOf';
import { isObjectLike } from '../jsutils/isObjectLike';
import type { Maybe } from '../jsutils/Maybe';
import { toObjMap } from '../jsutils/toObjMap';
Expand All @@ -24,7 +23,11 @@ import { GraphQLBoolean, GraphQLString } from './scalars';
* Test if the given value is a GraphQL directive.
*/
export function isDirective(directive: unknown): directive is GraphQLDirective {
return instanceOf(directive, GraphQLDirective);
return (
typeof directive === 'object' &&
directive != null &&
isGraphQLDirectiveSymbol in directive
);
}

export function assertDirective(directive: unknown): GraphQLDirective {
Expand All @@ -49,11 +52,14 @@ export interface GraphQLDirectiveExtensions {
[attributeName: string]: unknown;
}

const isGraphQLDirectiveSymbol = Symbol.for('GraphQLDirective');

/**
* Directives are used by the GraphQL runtime as a way of modifying execution
* behavior. Type system creators will usually not create these directly.
*/
export class GraphQLDirective {
[isGraphQLDirectiveSymbol]: true = true;
name: string;
description: Maybe<string>;
locations: ReadonlyArray<DirectiveLocation>;
Expand Down
8 changes: 6 additions & 2 deletions src/type/schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { devAssert } from '../jsutils/devAssert';
import { inspect } from '../jsutils/inspect';
import { instanceOf } from '../jsutils/instanceOf';
import { isObjectLike } from '../jsutils/isObjectLike';
import type { Maybe } from '../jsutils/Maybe';
import type { ObjMap } from '../jsutils/ObjMap';
Expand Down Expand Up @@ -43,7 +42,9 @@ import {
* Test if the given value is a GraphQL schema.
*/
export function isSchema(schema: unknown): schema is GraphQLSchema {
return instanceOf(schema, GraphQLSchema);
return (
typeof schema === 'object' && schema != null && isSchemaSymbol in schema
);
}

export function assertSchema(schema: unknown): GraphQLSchema {
Expand All @@ -66,6 +67,8 @@ export interface GraphQLSchemaExtensions {
[attributeName: string]: unknown;
}

const isSchemaSymbol = Symbol.for('GraphQLSchema');

/**
* Schema Definition
*
Expand Down Expand Up @@ -139,6 +142,7 @@ export class GraphQLSchema {
extensions: Readonly<GraphQLSchemaExtensions>;
astNode: Maybe<SchemaDefinitionNode>;
extensionASTNodes: ReadonlyArray<SchemaExtensionNode>;
[isSchemaSymbol]: true = true;

// Used as a cache for validateSchema().
__validationErrors: Maybe<ReadonlyArray<GraphQLError>>;
Expand Down
4 changes: 2 additions & 2 deletions src/utilities/coerceInputValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { addPath, pathToArray } from '../jsutils/Path';
import { printPathArray } from '../jsutils/printPathArray';
import { suggestionList } from '../jsutils/suggestionList';

import { GraphQLError } from '../error/GraphQLError';
import { GraphQLError, isGraphQLError } from '../error/GraphQLError';

import type { GraphQLInputType } from '../type/definition';
import {
Expand Down Expand Up @@ -154,7 +154,7 @@ function coerceInputValueImpl(
try {
parseResult = type.parseValue(inputValue);
} catch (error) {
if (error instanceof GraphQLError) {
if (isGraphQLError(error)) {
onError(pathToArray(path), inputValue, error);
} else {
onError(
Expand Down
4 changes: 2 additions & 2 deletions src/validation/rules/ValuesOfCorrectTypeRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { inspect } from '../../jsutils/inspect';
import { keyMap } from '../../jsutils/keyMap';
import { suggestionList } from '../../jsutils/suggestionList';

import { GraphQLError } from '../../error/GraphQLError';
import { GraphQLError, isGraphQLError } from '../../error/GraphQLError';

import type { ValueNode } from '../../language/ast';
import { print } from '../../language/printer';
Expand Down Expand Up @@ -138,7 +138,7 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void {
}
} catch (error) {
const typeStr = inspect(locationType);
if (error instanceof GraphQLError) {
if (isGraphQLError(error)) {
context.reportError(error);
} else {
context.reportError(
Expand Down

0 comments on commit b71648f

Please sign in to comment.