Skip to content

Commit a5bbe71

Browse files
Convert all non-reachable exceptions into invariants (#2067)
1 parent e58762a commit a5bbe71

13 files changed

+53
-30
lines changed

resources/inline-invariant.js

+25-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ module.exports = function inlineInvariant(context) {
2121
(%%cond%%) || devAssert(0, %%args%%)
2222
`);
2323

24+
const t = context.types;
2425
return {
2526
visitor: {
2627
CallExpression(path) {
@@ -38,13 +39,35 @@ module.exports = function inlineInvariant(context) {
3839
const calleeName = node.callee.name;
3940
if (calleeName === 'invariant') {
4041
const [cond, args] = node.arguments;
41-
path.addComment('leading', ' istanbul ignore next ');
42-
path.replaceWith(invariantTemplate({ cond, args }));
42+
43+
// Check if it is unreachable invariant: "invariant(false, ...)"
44+
if (cond.type === 'BooleanLiteral' && cond.value === false) {
45+
addIstanbulIgnoreElse(path);
46+
} else {
47+
path.replaceWith(invariantTemplate({ cond, args }));
48+
}
4349
} else if (calleeName === 'devAssert') {
4450
const [cond, args] = node.arguments;
4551
path.replaceWith(assertTemplate({ cond, args }));
4652
}
53+
54+
path.addComment('leading', ' istanbul ignore next ');
4755
},
4856
},
4957
};
58+
59+
function addIstanbulIgnoreElse(path) {
60+
const parentStatement = path.getStatementParent();
61+
const previousStatement =
62+
parentStatement.container[parentStatement.key - 1];
63+
if (previousStatement.type === 'IfStatement') {
64+
let lastIf = previousStatement;
65+
while (lastIf.alternate && lastIf.alternate.type === 'IfStatement') {
66+
lastIf = lastIf.alternate;
67+
}
68+
if (lastIf.alternate == null) {
69+
t.addComment(lastIf, 'leading', ' istanbul ignore else ');
70+
}
71+
}
72+
}
5073
};

src/execution/execute.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { forEach, isCollection } from 'iterall';
44

55
import inspect from '../jsutils/inspect';
66
import memoize3 from '../jsutils/memoize3';
7+
import invariant from '../jsutils/invariant';
78
import devAssert from '../jsutils/devAssert';
89
import isInvalid from '../jsutils/isInvalid';
910
import isNullish from '../jsutils/isNullish';
@@ -872,11 +873,10 @@ function completeValue(
872873
}
873874

874875
// Not reachable. All possible output types have been considered.
875-
/* istanbul ignore next */
876-
throw new Error(
877-
`Cannot complete value of unexpected output type: "${inspect(
878-
(returnType: empty),
879-
)}".`,
876+
invariant(
877+
false,
878+
'Cannot complete value of unexpected output type: ' +
879+
inspect((returnType: empty)),
880880
);
881881
}
882882

src/type/introspection.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import objectValues from '../polyfills/objectValues';
44

55
import inspect from '../jsutils/inspect';
6+
import invariant from '../jsutils/invariant';
67

78
import { print } from '../language/printer';
89
import { DirectiveLocation } from '../language/directiveLocation';
@@ -208,8 +209,7 @@ export const __Type = new GraphQLObjectType({
208209
}
209210

210211
// Not reachable. All possible types have been considered.
211-
/* istanbul ignore next */
212-
throw new Error(`Unexpected type: "${inspect((type: empty))}".`);
212+
invariant(false, `Unexpected type: "${inspect((type: empty))}".`);
213213
},
214214
},
215215
name: {

src/utilities/astFromValue.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { forEach, isCollection } from 'iterall';
55
import objectValues from '../polyfills/objectValues';
66

77
import inspect from '../jsutils/inspect';
8+
import invariant from '../jsutils/invariant';
89
import isNullish from '../jsutils/isNullish';
910
import isInvalid from '../jsutils/isInvalid';
1011
import isObjectLike from '../jsutils/isObjectLike';
@@ -137,8 +138,7 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode {
137138
}
138139

139140
// Not reachable. All possible input types have been considered.
140-
/* istanbul ignore next */
141-
throw new Error(`Unexpected input type: "${inspect((type: empty))}".`);
141+
invariant(false, 'Unexpected input type: ' + inspect((type: empty)));
142142
}
143143

144144
/**

src/utilities/buildASTSchema.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import objectValues from '../polyfills/objectValues';
44

55
import keyMap from '../jsutils/keyMap';
66
import inspect from '../jsutils/inspect';
7+
import invariant from '../jsutils/invariant';
78
import devAssert from '../jsutils/devAssert';
89
import keyValMap from '../jsutils/keyValMap';
910
import { type ObjMap } from '../jsutils/ObjMap';
@@ -313,9 +314,9 @@ export class ASTDefinitionBuilder {
313314
}
314315

315316
// Not reachable. All possible type definition nodes have been considered.
316-
/* istanbul ignore next */
317-
throw new Error(
318-
`Unexpected type definition node: "${inspect((astNode: empty))}".`,
317+
invariant(
318+
false,
319+
'Unexpected type definition node: ' + inspect((astNode: empty)),
319320
);
320321
}
321322

src/utilities/coerceValue.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { forEach, isCollection } from 'iterall';
55
import objectValues from '../polyfills/objectValues';
66

77
import inspect from '../jsutils/inspect';
8+
import invariant from '../jsutils/invariant';
89
import didYouMean from '../jsutils/didYouMean';
910
import isObjectLike from '../jsutils/isObjectLike';
1011
import suggestionList from '../jsutils/suggestionList';
@@ -195,8 +196,7 @@ export function coerceValue(
195196
}
196197

197198
// Not reachable. All possible input types have been considered.
198-
/* istanbul ignore next */
199-
throw new Error(`Unexpected input type: "${inspect((type: empty))}".`);
199+
invariant(false, 'Unexpected input type: ' + inspect((type: empty)));
200200
}
201201

202202
function ofValue(value) {

src/utilities/extendSchema.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import objectValues from '../polyfills/objectValues';
55

66
import inspect from '../jsutils/inspect';
77
import mapValue from '../jsutils/mapValue';
8+
import invariant from '../jsutils/invariant';
89
import devAssert from '../jsutils/devAssert';
910
import keyValMap from '../jsutils/keyValMap';
1011

@@ -258,8 +259,7 @@ export function extendSchema(
258259
}
259260

260261
// Not reachable. All possible types have been considered.
261-
/* istanbul ignore next */
262-
throw new Error(`Unexpected type: "${inspect((type: empty))}".`);
262+
invariant(false, 'Unexpected type: ' + inspect((type: empty)));
263263
}
264264

265265
function extendDirective(directive: GraphQLDirective): GraphQLDirective {

src/utilities/findBreakingChanges.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -512,8 +512,7 @@ function typeKindName(type: GraphQLNamedType): string {
512512
}
513513

514514
// Not reachable. All possible named types have been considered.
515-
/* istanbul ignore next */
516-
throw new TypeError(`Unexpected type: ${inspect((type: empty))}.`);
515+
invariant(false, 'Unexpected type: ' + inspect((type: empty)));
517516
}
518517

519518
function stringifyValue(value: mixed, type: GraphQLInputType): string {

src/utilities/lexicographicSortSchema.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import objectValues from '../polyfills/objectValues';
44

55
import inspect from '../jsutils/inspect';
6+
import invariant from '../jsutils/invariant';
67
import keyValMap from '../jsutils/keyValMap';
78
import { type ObjMap } from '../jsutils/ObjMap';
89

@@ -137,8 +138,7 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema {
137138
}
138139

139140
// Not reachable. All possible types have been considered.
140-
/* istanbul ignore next */
141-
throw new Error(`Unexpected type: "${inspect((type: empty))}".`);
141+
invariant(false, 'Unexpected type: ' + inspect((type: empty)));
142142
}
143143
}
144144

src/utilities/schemaPrinter.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import flatMap from '../polyfills/flatMap';
44
import objectValues from '../polyfills/objectValues';
55

66
import inspect from '../jsutils/inspect';
7+
import invariant from '../jsutils/invariant';
78

89
import { print } from '../language/printer';
910
import { printBlockString } from '../language/blockString';
@@ -173,8 +174,7 @@ export function printType(type: GraphQLNamedType, options?: Options): string {
173174
}
174175

175176
// Not reachable. All possible types have been considered.
176-
/* istanbul ignore next */
177-
throw new Error(`Unexpected type: "${inspect((type: empty))}".`);
177+
invariant(false, 'Unexpected type: ' + inspect((type: empty)));
178178
}
179179

180180
function printScalar(type: GraphQLScalarType, options): string {

src/utilities/typeFromAST.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// @flow strict
22

33
import inspect from '../jsutils/inspect';
4+
import invariant from '../jsutils/invariant';
45

56
import { Kind } from '../language/kinds';
67
import {
@@ -52,6 +53,5 @@ export function typeFromAST(schema, typeNode) {
5253
}
5354

5455
// Not reachable. All possible type nodes have been considered.
55-
/* istanbul ignore next */
56-
throw new Error(`Unexpected type node: "${inspect((typeNode: empty))}".`);
56+
invariant(false, 'Unexpected type node: ' + inspect((typeNode: empty)));
5757
}

src/utilities/valueFromAST.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import objectValues from '../polyfills/objectValues';
44

55
import keyMap from '../jsutils/keyMap';
66
import inspect from '../jsutils/inspect';
7+
import invariant from '../jsutils/invariant';
78
import isInvalid from '../jsutils/isInvalid';
89
import { type ObjMap } from '../jsutils/ObjMap';
910

@@ -160,8 +161,7 @@ export function valueFromAST(
160161
}
161162

162163
// Not reachable. All possible input types have been considered.
163-
/* istanbul ignore next */
164-
throw new Error(`Unexpected input type: "${inspect((type: empty))}".`);
164+
invariant(false, 'Unexpected input type: ' + inspect((type: empty)));
165165
}
166166

167167
// Returns true if the provided valueNode is a variable which is not defined

src/utilities/valueFromASTUntyped.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// @flow strict
22

33
import inspect from '../jsutils/inspect';
4+
import invariant from '../jsutils/invariant';
45
import keyValMap from '../jsutils/keyValMap';
56
import isInvalid from '../jsutils/isInvalid';
67
import { type ObjMap } from '../jsutils/ObjMap';
@@ -56,6 +57,5 @@ export function valueFromASTUntyped(
5657
}
5758

5859
// Not reachable. All possible value nodes have been considered.
59-
/* istanbul ignore next */
60-
throw new Error(`Unexpected value node: "${inspect((valueNode: empty))}".`);
60+
invariant(false, 'Unexpected value node: ' + inspect((valueNode: empty)));
6161
}

0 commit comments

Comments
 (0)