Skip to content

Commit f07ec24

Browse files
Flow: enable 'sketchy-null-bool' lint rule (#2371)
1 parent d447244 commit f07ec24

31 files changed

+83
-97
lines changed

.flowconfig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
[libs]
1111

1212
[lints]
13-
sketchy-null-bool=off
13+
sketchy-null-bool=error
1414
sketchy-null-string=error
1515
sketchy-null-number=error
1616
sketchy-null-mixed=error
@@ -35,6 +35,7 @@ uninitialized-instance-property=error
3535
include_warnings=true
3636
module.use_strict=true
3737
babel_loose_array_spread=true
38+
esproposal.optional_chaining=enable
3839
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)?)\\)
3940
suppress_comment=\\(.\\|\n\\)*\\$DisableFlowOnNegativeTest
4041

src/error/GraphQLError.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,7 @@ export class GraphQLError extends Error {
9999
// Compute locations in the source for the given nodes/positions.
100100
let _source = source;
101101
if (!_source && _nodes) {
102-
const node = _nodes[0];
103-
_source = node && node.loc && node.loc.source;
102+
_source = _nodes[0].loc?.source;
104103
}
105104

106105
let _positions = positions;
@@ -188,7 +187,7 @@ export class GraphQLError extends Error {
188187
});
189188

190189
// Include (non-enumerable) stack trace.
191-
if (originalError && originalError.stack) {
190+
if (originalError?.stack) {
192191
Object.defineProperty(this, 'stack', {
193192
value: originalError.stack,
194193
writable: true,

src/error/__tests__/GraphQLError-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const source = new Source(dedent`
1919
`);
2020
const ast = parse(source);
2121
const operationNode = ast.definitions[0];
22-
invariant(operationNode && operationNode.kind === Kind.OPERATION_DEFINITION);
22+
invariant(operationNode.kind === Kind.OPERATION_DEFINITION);
2323
const fieldNode = operationNode.selectionSet.selections[0];
2424
invariant(fieldNode);
2525

@@ -161,7 +161,7 @@ describe('printError', () => {
161161
),
162162
);
163163
const opA = docA.definitions[0];
164-
invariant(opA && opA.kind === Kind.OBJECT_TYPE_DEFINITION && opA.fields);
164+
invariant(opA.kind === Kind.OBJECT_TYPE_DEFINITION && opA.fields);
165165
const fieldA = opA.fields[0];
166166

167167
const docB = parse(
@@ -175,7 +175,7 @@ describe('printError', () => {
175175
),
176176
);
177177
const opB = docB.definitions[0];
178-
invariant(opB && opB.kind === Kind.OBJECT_TYPE_DEFINITION && opB.fields);
178+
invariant(opB.kind === Kind.OBJECT_TYPE_DEFINITION && opB.fields);
179179
const fieldB = opB.fields[0];
180180

181181
const error = new GraphQLError('Example error with two nodes', [

src/error/locatedError.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ export function locatedError(
1616
): GraphQLError {
1717
// Note: this uses a brand-check to support GraphQL errors originating from
1818
// other contexts.
19-
if (originalError && Array.isArray(originalError.path)) {
19+
if (Array.isArray(originalError.path)) {
2020
return (originalError: any);
2121
}
2222

2323
return new GraphQLError(
24-
originalError && originalError.message,
25-
(originalError && (originalError: any).nodes) || nodes,
26-
originalError && (originalError: any).source,
27-
originalError && (originalError: any).positions,
24+
originalError.message,
25+
(originalError: any).nodes || nodes,
26+
(originalError: any).source,
27+
(originalError: any).positions,
2828
path,
2929
originalError,
3030
);

src/execution/__tests__/executor-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ describe('Execute: Handles basic execution tasks', () => {
292292
);
293293

294294
const operation = document.definitions[0];
295-
invariant(operation && operation.kind === Kind.OPERATION_DEFINITION);
295+
invariant(operation.kind === Kind.OPERATION_DEFINITION);
296296

297297
expect(resolvedInfo).to.include({
298298
fieldName: 'test',
@@ -1025,7 +1025,7 @@ describe('Execute: Handles basic execution tasks', () => {
10251025
name: 'SpecialType',
10261026
isTypeOf(obj, context) {
10271027
const result = obj instanceof Special;
1028-
return context && context.async ? Promise.resolve(result) : result;
1028+
return context?.async ? Promise.resolve(result) : result;
10291029
},
10301030
fields: { value: { type: GraphQLString } },
10311031
});

src/execution/execute.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ export function buildExecutionContext(
296296
];
297297
}
298298
operation = definition;
299-
} else if (definition.name && definition.name.value === operationName) {
299+
} else if (definition.name?.value === operationName) {
300300
operation = definition;
301301
}
302302
break;
@@ -554,7 +554,7 @@ function shouldIncludeNode(
554554
node,
555555
exeContext.variableValues,
556556
);
557-
if (skip && skip.if === true) {
557+
if (skip?.if === true) {
558558
return false;
559559
}
560560

@@ -563,7 +563,7 @@ function shouldIncludeNode(
563563
node,
564564
exeContext.variableValues,
565565
);
566-
if (include && include.if === false) {
566+
if (include?.if === false) {
567567
return false;
568568
}
569569
return true;

src/execution/values.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export function getVariableValues(
5050
inputs: { +[variable: string]: mixed, ... },
5151
options?: {| maxErrors?: number |},
5252
): CoercedVariableValues {
53-
const maxErrors = options && options.maxErrors;
53+
const maxErrors = options?.maxErrors;
5454
const errors = [];
5555
try {
5656
const coerced = coerceVariableValues(schema, varDefNodes, inputs, error => {

src/jsutils/isPromise.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ declare function isPromise(value: mixed): boolean %checks(value instanceof
99

1010
// eslint-disable-next-line no-redeclare
1111
export default function isPromise(value) {
12-
return value != null && typeof value.then === 'function';
12+
return typeof value?.then === 'function';
1313
}

src/language/__tests__/visitor-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ describe('Visitor', () => {
500500
'enter',
501501
node.kind,
502502
key,
503-
parent && parent.kind != null ? parent.kind : undefined,
503+
parent?.kind != null ? parent.kind : undefined,
504504
]);
505505

506506
checkVisitorFnArgs(ast, arguments);
@@ -512,7 +512,7 @@ describe('Visitor', () => {
512512
'leave',
513513
node.kind,
514514
key,
515-
parent && parent.kind != null ? parent.kind : undefined,
515+
parent?.kind != null ? parent.kind : undefined,
516516
]);
517517

518518
expect(argsStack.pop()).to.deep.equal([...arguments]);

src/language/parser.js

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ export function parseType(
164164
}
165165

166166
class Parser {
167-
_options: ParseOptions;
167+
_options: ?ParseOptions;
168168
_lexer: Lexer;
169169

170170
constructor(source: string | Source, options?: ParseOptions) {
@@ -175,12 +175,7 @@ class Parser {
175175
);
176176

177177
this._lexer = new Lexer(sourceObj);
178-
this._options = options || {
179-
noLocation: false,
180-
allowLegacySDLEmptyFields: false,
181-
allowLegacySDLImplementsInterfaces: false,
182-
experimentalFragmentVariables: false,
183-
};
178+
this._options = options;
184179
}
185180

186181
/**
@@ -483,7 +478,7 @@ class Parser {
483478
// Experimental support for defining variables within fragments changes
484479
// the grammar of FragmentDefinition:
485480
// - fragment FragmentName VariableDefinitions? on TypeCondition Directives? SelectionSet
486-
if (this._options.experimentalFragmentVariables) {
481+
if (this._options?.experimentalFragmentVariables === true) {
487482
return {
488483
kind: Kind.FRAGMENT_DEFINITION,
489484
name: this.parseFragmentName(),
@@ -869,7 +864,7 @@ class Parser {
869864
} while (
870865
this.expectOptionalToken(TokenKind.AMP) ||
871866
// Legacy support for the SDL?
872-
(this._options.allowLegacySDLImplementsInterfaces &&
867+
(this._options?.allowLegacySDLImplementsInterfaces === true &&
873868
this.peek(TokenKind.NAME))
874869
);
875870
}
@@ -882,7 +877,7 @@ class Parser {
882877
parseFieldsDefinition(): Array<FieldDefinitionNode> {
883878
// Legacy support for the SDL?
884879
if (
885-
this._options.allowLegacySDLEmptyFields &&
880+
this._options?.allowLegacySDLEmptyFields === true &&
886881
this.peek(TokenKind.BRACE_L) &&
887882
this._lexer.lookahead().kind === TokenKind.BRACE_R
888883
) {
@@ -1403,7 +1398,7 @@ class Parser {
14031398
* the source that created a given parsed object.
14041399
*/
14051400
loc(startToken: Token): Location | void {
1406-
if (!this._options.noLocation) {
1401+
if (this._options?.noLocation !== true) {
14071402
return new Location(
14081403
startToken,
14091404
this._lexer.lastToken,

src/subscription/__tests__/mapAsyncIterator-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ describe('mapAsyncIterator', () => {
273273
} catch (e) {
274274
caughtError = e;
275275
}
276-
expect(caughtError && caughtError.message).to.equal('Goodbye');
276+
expect(caughtError?.message).to.equal('Goodbye');
277277
});
278278

279279
it('maps over thrown errors if second callback provided', async () => {
@@ -295,7 +295,7 @@ describe('mapAsyncIterator', () => {
295295

296296
const result = await doubles.next();
297297
expect(result.value).to.be.instanceof(Error);
298-
expect(result.value && result.value.message).to.equal('Goodbye');
298+
expect(result.value?.message).to.equal('Goodbye');
299299
expect(result.done).to.equal(false);
300300

301301
expect(await doubles.next()).to.deep.equal({

src/subscription/__tests__/subscribe-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ async function expectPromiseToThrow(promise, message) {
142142
/* istanbul ignore next */
143143
expect.fail('promise should have thrown but did not');
144144
} catch (error) {
145-
expect(error && error.message).to.equal(message);
145+
expect(error?.message).to.equal(message);
146146
}
147147
}
148148

src/type/directives.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class GraphQLDirective {
6565
this.name = config.name;
6666
this.description = config.description;
6767
this.locations = config.locations;
68-
this.isRepeatable = config.isRepeatable != null && config.isRepeatable;
68+
this.isRepeatable = config.isRepeatable || false;
6969
this.extensions = config.extensions && toObjMap(config.extensions);
7070
this.astNode = config.astNode;
7171

src/type/schema.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export class GraphQLSchema {
138138
constructor(config: $ReadOnly<GraphQLSchemaConfig>): void {
139139
// If this schema was built from a source known to be valid, then it may be
140140
// marked with assumeValid to avoid an additional type system validation.
141-
if (config && config.assumeValid) {
141+
if (config.assumeValid === true) {
142142
this.__validationErrors = [];
143143
} else {
144144
this.__validationErrors = undefined;

src/type/validate.js

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ function validateDirectives(context: SchemaValidationContext): void {
156156
if (!isDirective(directive)) {
157157
context.reportError(
158158
`Expected directive but got: ${inspect(directive)}.`,
159-
directive && directive.astNode,
159+
directive?.astNode,
160160
);
161161
continue;
162162
}
@@ -204,7 +204,7 @@ function validateTypes(context: SchemaValidationContext): void {
204204
if (!isNamedType(type)) {
205205
context.reportError(
206206
`Expected GraphQL named type but got: ${inspect(type)}.`,
207-
type && type.astNode,
207+
type?.astNode,
208208
);
209209
continue;
210210
}
@@ -265,7 +265,7 @@ function validateFields(
265265
context.reportError(
266266
`The type of ${type.name}.${field.name} must be Output Type ` +
267267
`but got: ${inspect(field.type)}.`,
268-
field.astNode && field.astNode.type,
268+
field.astNode?.type,
269269
);
270270
}
271271

@@ -281,7 +281,7 @@ function validateFields(
281281
context.reportError(
282282
`The type of ${type.name}.${field.name}(${argName}:) must be Input ` +
283283
`Type but got: ${inspect(arg.type)}.`,
284-
arg.astNode && arg.astNode.type,
284+
arg.astNode?.type,
285285
);
286286
}
287287
}
@@ -354,10 +354,7 @@ function validateTypeImplementsInterface(
354354
`Interface field ${iface.name}.${fieldName} expects type ` +
355355
`${inspect(ifaceField.type)} but ${type.name}.${fieldName} ` +
356356
`is type ${inspect(typeField.type)}.`,
357-
[
358-
ifaceField.astNode && ifaceField.astNode.type,
359-
typeField.astNode && typeField.astNode.type,
360-
],
357+
[ifaceField.astNode?.type, typeField.astNode?.type],
361358
);
362359
}
363360

@@ -384,10 +381,7 @@ function validateTypeImplementsInterface(
384381
`expects type ${inspect(ifaceArg.type)} but ` +
385382
`${type.name}.${fieldName}(${argName}:) is type ` +
386383
`${inspect(typeArg.type)}.`,
387-
[
388-
ifaceArg.astNode && ifaceArg.astNode.type,
389-
typeArg.astNode && typeArg.astNode.type,
390-
],
384+
[ifaceArg.astNode?.type, typeArg.astNode?.type],
391385
);
392386
}
393387

@@ -512,7 +506,7 @@ function validateInputFields(
512506
context.reportError(
513507
`The type of ${inputObj.name}.${field.name} must be Input Type ` +
514508
`but got: ${inspect(field.type)}.`,
515-
field.astNode && field.astNode.type,
509+
field.astNode?.type,
516510
);
517511
}
518512
}

src/utilities/__tests__/buildASTSchema-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ function cycleSDL(sdl, options = {}) {
5151
}
5252

5353
function printASTNode(obj) {
54-
invariant(obj != null && obj.astNode != null);
54+
invariant(obj?.astNode != null);
5555
return print(obj.astNode);
5656
}
5757

src/utilities/__tests__/extendSchema-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import { extendSchema } from '../extendSchema';
3737
import { buildSchema } from '../buildASTSchema';
3838

3939
function printExtensionNodes(obj) {
40-
invariant(obj && obj.extensionASTNodes);
40+
invariant(obj?.extensionASTNodes != null);
4141
return print({
4242
kind: Kind.DOCUMENT,
4343
definitions: obj.extensionASTNodes,
@@ -56,7 +56,7 @@ function printSchemaChanges(schema, extendedSchema) {
5656
}
5757

5858
function printASTNode(obj) {
59-
invariant(obj != null && obj.astNode != null);
59+
invariant(obj?.astNode != null);
6060
return print(obj.astNode);
6161
}
6262

src/utilities/astFromValue.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ import {
4747
export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode {
4848
if (isNonNullType(type)) {
4949
const astValue = astFromValue(value, type.ofType);
50-
if (astValue && astValue.kind === Kind.NULL) {
50+
if (astValue?.kind === Kind.NULL) {
5151
return null;
5252
}
5353
return astValue;

0 commit comments

Comments
 (0)