Skip to content

Commit

Permalink
Backport instanceOf Error Check Improvements
Browse files Browse the repository at this point in the history
This backports graphql#3172 to the `15.x.x` branch so that users of GraphQL
v15.x can take advantage of it. GraphQL v16.x has some breaking changes
and is not possible to run when you have other libraries depending on
the behavior of v15, such as GraphQL Code Generator.
  • Loading branch information
tubbo authored and IvanGoncharov committed Jun 20, 2021
1 parent 1611bbb commit 7b724c7
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 8 deletions.
32 changes: 29 additions & 3 deletions src/jsutils/__tests__/instanceOf-test.js
Expand Up @@ -4,19 +4,45 @@ import { describe, it } from 'mocha';
import instanceOf from '../instanceOf';

describe('instanceOf', () => {
it('allows instances to have share the same constructor name', () => {
function getMinifiedClass(tag: string) {
class SomeNameAfterMinification {
// $FlowFixMe[unsupported-syntax]
get [Symbol.toStringTag]() {
return tag;
}
}
return SomeNameAfterMinification;
}

const Foo = getMinifiedClass('Foo');
const Bar = getMinifiedClass('Bar');
expect(instanceOf(new Foo(), Bar)).to.equal(false);
expect(instanceOf(new Bar(), Foo)).to.equal(false);

const DuplicateOfFoo = getMinifiedClass('Foo');
expect(() => instanceOf(new DuplicateOfFoo(), Foo)).to.throw();
expect(() => instanceOf(new Foo(), DuplicateOfFoo)).to.throw();
});

it('fails with descriptive error message', () => {
function getFoo() {
class Foo {}
class Foo {
// $FlowFixMe[unsupported-syntax]
get [Symbol.toStringTag]() {
return 'Foo';
}
}
return Foo;
}
const Foo1 = getFoo();
const Foo2 = getFoo();

expect(() => instanceOf(new Foo1(), Foo2)).to.throw(
/^Cannot use Foo "\[object Object\]" from another module or realm./m,
/^Cannot use Foo "{}" from another module or realm./m,
);
expect(() => instanceOf(new Foo2(), Foo1)).to.throw(
/^Cannot use Foo "\[object Object\]" from another module or realm./m,
/^Cannot use Foo "{}" from another module or realm./m,
);
});
});
17 changes: 12 additions & 5 deletions src/jsutils/instanceOf.js
@@ -1,3 +1,5 @@
import inspect from './inspect';

/**
* A replacement for instanceof which includes an error warning when multi-realm
* constructors are detected.
Expand All @@ -20,12 +22,17 @@ export default process.env.NODE_ENV === 'production'
if (value instanceof constructor) {
return true;
}
if (value) {
const valueClass = value.constructor;
const className = constructor.name;
if (className && valueClass && valueClass.name === className) {
if (typeof value === 'object' && value !== null) {
const className = constructor.prototype[Symbol.toStringTag];
const valueClassName =
// We still need to support constructor's name to detect conflicts with older versions of this library.
Symbol.toStringTag in value
? value[Symbol.toStringTag]
: value.constructor?.name;
if (className === valueClassName) {
const stringifiedValue = inspect(value);
throw new Error(
`Cannot use ${className} "${value}" from another module or realm.
`Cannot use ${className} "${stringifiedValue}" from another module or realm.
Ensure that there is only one instance of "graphql" in the node_modules
directory. If different versions of "graphql" are the dependencies of other
Expand Down

0 comments on commit 7b724c7

Please sign in to comment.