10000 Enable `noUncheckedIndexedAccess` by louisscruz · Pull Request #3867 · graphql/graphql-js · GitHub
[go: up one dir, main page]

Skip to content

Enable noUncheckedIndexedAccess #3867

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: next
Choose a base branch
from
Open
10000
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Address all unchecked indexed access within source code
  • Loading branch information
louisscruz committed Mar 31, 2023
commit 451fee5d76d4b5f6a53eb4d24a57b780babff834
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
Loading
0