Skip to content
This repository has been archived by the owner on May 26, 2023. It is now read-only.

Commit

Permalink
Avoid relying on constructor.name for instanceOf error check.
Browse files Browse the repository at this point in the history
An improvement beyond graphql#1174, for non-production environments that enable
minification, such as NODE_ENV='staging'.

Since graphql-js goes to the trouble of providing a Symbol.toStringTag
property for most of the classes it exports, and that string is immune to
minification (unlike constructor.name), we should use it for error
checking in instanceOf(value, constructor) whenever the constructor
provides a tag, falling back to constructor.name and
value.constructor.name for constructors that do not define
Symbol.toStringTag (as before).

Motivating issue/investigation:
apollographql/apollo-client#7446 (comment)
  • Loading branch information
benjamn committed Jan 26, 2021
1 parent 3bce13f commit f9e1d0a
Showing 1 changed file with 19 additions and 3 deletions.
22 changes: 19 additions & 3 deletions src/jsutils/instanceOf.js
@@ -1,3 +1,5 @@
import { SYMBOL_TO_STRING_TAG } from '../polyfills/symbols';

/**
* A replacement for instanceof which includes an error warning when multi-realm
* constructors are detected.
Expand All @@ -21,9 +23,23 @@ export default process.env.NODE_ENV === 'production'
return true;
}
if (value) {
const valueClass = value.constructor;
const className = constructor.name;
if (className && valueClass && valueClass.name === className) {
const classTag = constructor?.prototype?.[SYMBOL_TO_STRING_TAG];
const className = classTag || constructor.name;
// When the constructor class defines a Symbol.toStringTag
// property, as most classes exported by graphql-js do, use it
// instead of constructor.name and value.constructor.name to
// detect module/realm duplication, since the Symbol.toStringTag
// string is immune to minification. This code runs only when
// process.env.NODE_ENV !== 'production', but minification is
// often enabled in non-production environments like 'staging'.
// In these environments, this error can be thrown mistakenly if
// we rely on constructor.name and value.constructor.name, since
// they could be minified to the same short string, even though
// value is legitimately _not_ instanceof constructor.
const valueName = classTag
? value[SYMBOL_TO_STRING_TAG]
: value.constructor?.name;
if (typeof className === 'string' && valueName === className) {
throw new Error(
`Cannot use ${className} "${value}" from another module or realm.
Expand Down

0 comments on commit f9e1d0a

Please sign in to comment.