Skip to content

Commit

Permalink
Address all unchecked indexed access within source code
Browse files Browse the repository at this point in the history
  • Loading branch information
louisscruz committed Mar 27, 2023
1 parent 34eaf2b commit 1bdd39a
Show file tree
Hide file tree
Showing 17 changed files with 153 additions and 60 deletions.
32 changes: 22 additions & 10 deletions src/execution/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,12 @@ function executeField(
asyncPayloadRecord?: AsyncPayloadRecord,
): PromiseOrValue<unknown> {
const errors = asyncPayloadRecord?.errors ?? exeContext.errors;
const fieldName = fieldNodes[0].name.value;
const firstFieldNode = fieldNodes[0];
invariant(firstFieldNode !== undefined);

const fieldName = fieldNodes[0]?.name.value;
invariant(fieldName !== undefined);

const fieldDef = exeContext.schema.getField(parentType, fieldName);
if (!fieldDef) {
return;
Expand All @@ -712,7 +717,7 @@ function executeField(
// TODO: find a way to memoize, in case this field is within a List type.
const args = getArgumentValues(
fieldDef,
fieldNodes[0],
firstFieldNode,
exeContext.variableValues,
);

Expand Down Expand Up @@ -974,11 +979,14 @@ function getStreamValues(
return;
}

const firstFieldNode = fieldNodes[0];
invariant(firstFieldNode !== undefined);

// validation only allows equivalent streams on multiple fields, so it is
// safe to only check the first fieldNode for the stream directive
const stream = getDirectiveValues(
GraphQLStreamDirective,
fieldNodes[0],
firstFieldNode,
exeContext.variableValues,
);

Expand Down Expand Up @@ -1497,27 +1505,31 @@ export const defaultTypeResolver: GraphQLTypeResolver<unknown, unknown> =

// Otherwise, test each possible type.
const possibleTypes = info.schema.getPossibleTypes(abstractType);
const promisedIsTypeOfResults = [];
const promisedIsTypeOfResults: Array<Promise<[string, boolean]>> = [];

for (let i = 0; i < possibleTypes.length; i++) {
const type = possibleTypes[i];
let type: GraphQLObjectType;

for (type of possibleTypes) {
if (type.isTypeOf) {
const isTypeOfResult = type.isTypeOf(value, contextValue, info);

if (isPromise(isTypeOfResult)) {
promisedIsTypeOfResults[i] = isTypeOfResult;
const possibleTypeName = type.name;
promisedIsTypeOfResults.push(
isTypeOfResult.then((result) => [possibleTypeName, result]),
);
} else if (isTypeOfResult) {
return type.name;
}
}
}

if (promisedIsTypeOfResults.length) {
// QUESTION: Can this be faster if Promise.any or Promise.race is used instead?
return Promise.all(promisedIsTypeOfResults).then((isTypeOfResults) => {
for (let i = 0; i < isTypeOfResults.length; i++) {
if (isTypeOfResults[i]) {
return possibleTypes[i].name;
for (const [name, result] of isTypeOfResults) {
if (result) {
return name;
}
}
});
Expand Down
7 changes: 4 additions & 3 deletions src/jsutils/formatList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ export function andList(items: ReadonlyArray<string>): string {
}

function formatList(conjunction: string, items: ReadonlyArray<string>): string {
invariant(items.length !== 0);
const firstItem = items[0];
invariant(firstItem !== undefined);

switch (items.length) {
case 1:
return items[0];
return firstItem;
case 2:
return items[0] + ' ' + conjunction + ' ' + items[1];
return firstItem + ' ' + conjunction + ' ' + items[1];
}

const allButLast = items.slice(0, -1);
Expand Down
10 changes: 4 additions & 6 deletions src/jsutils/mapValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ export function mapValue<T, V>(
map: ReadOnlyObjMap<T>,
fn: (value: T, key: string) => V,
): ObjMap<V> {
const result = Object.create(null);

for (const key of Object.keys(map)) {
result[key] = fn(map[key], key);
}
return result;
return Object.entries(map).reduce((accumulator, [key, value]) => {
accumulator[key] = fn(value, key);
return accumulator;
}, Object.create(null));
}
7 changes: 6 additions & 1 deletion src/jsutils/promiseForObject.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { invariant } from './invariant.js';
import type { ObjMap } from './ObjMap.js';

/**
Expand All @@ -15,8 +16,12 @@ export async function promiseForObject<T>(

const resolvedValues = await Promise.all(values);
const resolvedObject = Object.create(null);

for (let i = 0; i < keys.length; ++i) {
resolvedObject[keys[i]] = resolvedValues[i];
const key = keys[i];
invariant(key !== undefined);

resolvedObject[key] = resolvedValues[i];
}
return resolvedObject;
}
35 changes: 29 additions & 6 deletions src/jsutils/suggestionList.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { invariant } from './invariant.js';
import { naturalCompare } from './naturalCompare.js';

/**
Expand Down Expand Up @@ -93,19 +94,34 @@ class LexicalDistance {
const upRow = rows[(i - 1) % 3];
const currentRow = rows[i % 3];

invariant(upRow !== undefined);
invariant(currentRow !== undefined);

let smallestCell = (currentRow[0] = i);
for (let j = 1; j <= bLength; j++) {
const cost = a[i - 1] === b[j - 1] ? 0 : 1;

const deleteTarget = upRow[j];
const currentRowTarget = currentRow[j - 1];
const substituteTarget = upRow[j - 1];

invariant(deleteTarget !== undefined);
invariant(currentRowTarget !== undefined);
invariant(substituteTarget !== undefined);

let currentCell = Math.min(
upRow[j] + 1, // delete
currentRow[j - 1] + 1, // insert
upRow[j - 1] + cost, // substitute
deleteTarget + 1, // delete
currentRowTarget + 1, // insert
substituteTarget + cost, // substitute
);

if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
// transposition
const doubleDiagonalCell = rows[(i - 2) % 3][j - 2];
const targetedRow = rows[(i - 2) % 3];
invariant(targetedRow !== undefined);
const doubleDiagonalCell = targetedRow[j - 2];
invariant(doubleDiagonalCell !== undefined);

currentCell = Math.min(currentCell, doubleDiagonalCell + 1);
}

Expand All @@ -122,8 +138,15 @@ class LexicalDistance {
}
}

const distance = rows[aLength % 3][bLength];
return distance <= threshold ? distance : undefined;
const targetedRow = rows[aLength % 3];

invariant(targetedRow !== undefined);

const distance = targetedRow[bLength];

return distance !== undefined && distance <= threshold
? distance
: undefined;
}
}

Expand Down
7 changes: 3 additions & 4 deletions src/language/blockString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,11 @@ export function dedentBlockStringLines(
let firstNonEmptyLine = null;
let lastNonEmptyLine = -1;

for (let i = 0; i < lines.length; ++i) {
const line = lines[i];
lines.forEach((line, i) => {
const indent = leadingWhitespace(line);

if (indent === line.length) {
continue; // skip empty lines
return; // skip empty lines
}

firstNonEmptyLine ??= i;
Expand All @@ -29,7 +28,7 @@ export function dedentBlockStringLines(
if (i !== 0 && indent < commonIndent) {
commonIndent = indent;
}
}
});

return (
lines
Expand Down
36 changes: 28 additions & 8 deletions src/language/printLocation.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { invariant } from '../jsutils/invariant.js';

import type { Location } from './ast.js';
import type { SourceLocation } from './location.js';
import { getLocation } from './location.js';
Expand Down Expand Up @@ -35,35 +37,53 @@ export function printSourceLocation(
const locationLine = lines[lineIndex];

// Special case for minified documents
if (locationLine.length > 120) {
if (locationLine !== undefined && locationLine.length > 120) {
const subLineIndex = Math.floor(columnNum / 80);
const subLineColumnNum = columnNum % 80;
const subLines: Array<string> = [];
for (let i = 0; i < locationLine.length; i += 80) {
subLines.push(locationLine.slice(i, i + 80));
}

const firstSubLine = subLines[0];
const nextSubLines = subLines.slice(1, subLineIndex + 1);
const nextSubLine = subLines[subLineIndex + 1];

invariant(firstSubLine !== undefined);
// invariant(nextSubLine !== undefined);

return (
locationStr +
printPrefixedLines([
[`${lineNum} |`, subLines[0]],
...subLines
.slice(1, subLineIndex + 1)
.map((subLine) => ['|', subLine] as const),
[`${lineNum} |`, firstSubLine],
...nextSubLines.map<[string, string]>((subLine) => ['|', subLine]),
['|', '^'.padStart(subLineColumnNum)],
['|', subLines[subLineIndex + 1]],
// TODO: This assertion can be removed if the above invariant is comment in.
['|', nextSubLine as string],
])
);
}

const previousLine = lines[lineIndex - 1];
const nextLine = lines[lineIndex + 1];

// TODO: With the way the types are set up, we should be able to
// comment these in, but doing so breaks tests.
//
// invariant(previousLine !== undefined);
// invariant(nextLine !== undefined);
invariant(locationLine !== undefined);

return (
locationStr +
printPrefixedLines([
// Lines specified like this: ["prefix", "string"],
[`${lineNum - 1} |`, lines[lineIndex - 1]],
// TODO: This assertion can be removed if the above invariant is comment in.
[`${lineNum - 1} |`, previousLine as string],
[`${lineNum} |`, locationLine],
['|', '^'.padStart(columnNum)],
[`${lineNum + 1} |`, lines[lineIndex + 1]],
// TODO: This assertion can be removed if the above invariant is comment in.
[`${lineNum + 1} |`, nextLine as string],
])
);
}
Expand Down
12 changes: 11 additions & 1 deletion src/language/printString.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { invariant } from '../jsutils/invariant.js';

/**
* Prints a string as a GraphQL StringValue literal. Replaces control characters
* and excluded characters (" U+0022 and \\ U+005C) with escape sequences.
Expand All @@ -10,7 +12,15 @@ export function printString(str: string): string {
const escapedRegExp = /[\x00-\x1f\x22\x5c\x7f-\x9f]/g;

function escapedReplacer(str: string): string {
return escapeSequences[str.charCodeAt(0)];
const firstCharacter = str.charCodeAt(0);

invariant(firstCharacter !== undefined);

const replacer = escapeSequences[firstCharacter];

invariant(replacer !== undefined);

return replacer;
}

// prettier-ignore
Expand Down
6 changes: 3 additions & 3 deletions src/language/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,12 +319,12 @@ export function visitInParallel(
const enterList = new Array(visitors.length).fill(undefined);
const leaveList = new Array(visitors.length).fill(undefined);

for (let i = 0; i < visitors.length; ++i) {
const { enter, leave } = getEnterLeaveForKind(visitors[i], kind);
visitors.forEach((visitor, i) => {
const { enter, leave } = getEnterLeaveForKind(visitor, kind);
hasVisitor ||= enter != null || leave != null;
enterList[i] = enter;
leaveList[i] = leave;
}
});

if (!hasVisitor) {
continue;
Expand Down
7 changes: 5 additions & 2 deletions src/utilities/lexicographicSortSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,11 @@ function sortObjMap<T, R>(
sortValueFn: (value: T) => R,
): ObjMap<R> {
const sortedMap = Object.create(null);
for (const key of Object.keys(map).sort(naturalCompare)) {
sortedMap[key] = sortValueFn(map[key]);

for (const [key, value] of Object.entries(map).sort(
([firstKey], [secondKey]) => naturalCompare(firstKey, secondKey),
)) {
sortedMap[key] = sortValueFn(value);
}
return sortedMap;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { invariant } from '../../jsutils/invariant.js';

import { GraphQLError } from '../../error/GraphQLError.js';

import type { DirectiveNode } from '../../language/ast.js';
Expand Down Expand Up @@ -50,6 +52,8 @@ export function DeferStreamDirectiveOnValidOperationsRule(
Directive(node, _key, _parent, _path, ancestors) {
const definitionNode = ancestors[2];

invariant(definitionNode !== undefined);

if (
'kind' in definitionNode &&
((definitionNode.kind === Kind.FRAGMENT_DEFINITION &&
Expand Down
2 changes: 2 additions & 0 deletions src/validation/rules/KnownDirectivesRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ function getDirectiveLocationForASTPath(
ancestors: ReadonlyArray<ASTNode | ReadonlyArray<ASTNode>>,
): DirectiveLocation | undefined {
const appliedTo = ancestors[ancestors.length - 1];
invariant(appliedTo !== undefined);
invariant('kind' in appliedTo);

switch (appliedTo.kind) {
Expand Down Expand Up @@ -115,6 +116,7 @@ function getDirectiveLocationForASTPath(
return DirectiveLocation.INPUT_OBJECT;
case Kind.INPUT_VALUE_DEFINITION: {
const parentNode = ancestors[ancestors.length - 3];
invariant(parentNode !== undefined);
invariant('kind' in parentNode);
return parentNode.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION
? DirectiveLocation.INPUT_FIELD_DEFINITION
Expand Down

0 comments on commit 1bdd39a

Please sign in to comment.