Skip to content

Commit

Permalink
enable typescript strict mode (#3010)
Browse files Browse the repository at this point in the history
* enable noImplicitThis

* enable `strictBindCallApply`

* enable `strictFunctionTypes` 1: testing

* enable `strictFunctionTypes` 2: utils

* enable strictFunctionTypes 3: schema

* enable strictFunctionTypes 4: batch-execute

* enable strictFunctionTypes 5 `load`

* enable strictFunctionTypes 6 `loaders/url`

* enable strictFunctionTypes 7 `webpack-loader`

* enable strictFunctionTypes 8 `links`

* enable strictFunctionTypes 9 `delegate` and `batch-delegate`

* enable `strictFunctionTypes` 10 `wrap`

* enable `strictFunctionTypes` 11 `stitch` and `stitching-directive`

* enable `strictFunctionTypes` final tsconfig

* remove unnecessary generic params

* enable `strictNullChecks` 1 `utils`

* enable `strictNullChecks` 2 `schema`

* enable `strictNullChecks` 3 `resolvers-composition`

* enable `strictNullChecks` 4 `webpack-loader`

* enable `strictNullChecks` 5 `batch-execute`

* enable `strictNullChecks` 6 `graphql-tag-plug`

* enable `strictNullChecks` 7 `import`

* enable `strictNullChecks` 8 `loaders/url`

* enable `strictNullChecks` 8 `loaders/prisma`

* enable `strictNullChecks` 8 `loaders/module`

* enable `strictNullChecks` 9 `loaders/github`

* enable `strictNullChecks` 12 `loaders/code-file`

* enable `strictNullChecks` 13 `load`

* enable `strictNullChecks` 14 `delegate`

* enable `strictNullChecks` 15 `batch-delegate`

* interlude: move commonly used stuff to testing folder

* enable `strictNullChecks` 16 `wrap`

* enable `strictNullChecks` 17 `stitch`

* enable `strictNullChecks` 18 `load-files`

* enable `strictNullChecks` 19 `load-typedefs`

* enable `strictNullChecks` 20 `merge`

* enable `strictNullChecks` 21 `node-require`

* enable `strictNullChecks` 22 `mock`

* enable `strictNullChecks` 22 `stitching-directive`

* enable `strictNullChecks` flag in tsconfig

* fix: graphql-js 14 compat

* fix `strictPropertyInitialization` errors

* enable strictPropertyInitialization rule

* strict mode!!!

* enable `noPropertyAccessFromIndexSignature`

* enable `noFallthroughCasesInSwitch` and `noPropertyAccessFromIndexSignature`

* Add strict to new changes

* fix: remove casts as upstream issue is fixed

* fix: throw if we cannot identify the operation type.

#3010 (comment)
#3010 (comment)

* fix: change wording of error

#3010 (comment)

* fix: make error message more clear

#3010 (comment)

* refactor: use null/undefined instead of falsey check

* fix: assert operation from document

#3010 (comment)

* fix: type narrowing not working due to generics

#3010 (comment)

* fix: apply feedback for relocateError

* Make wrapSchema generic. Fix #3064 (#1)

* Fix Build

Co-authored-by: Arda TANRIKULU <ardatanrikulu@gmail.com>
Co-authored-by: Augustin Le Fèvre <augustin.public@gmail.com>
  • Loading branch information
3 people authored Jun 21, 2021
1 parent a05e4f8 commit 806faae
Show file tree
Hide file tree
Showing 204 changed files with 2,794 additions and 1,615 deletions.
28 changes: 22 additions & 6 deletions packages/batch-delegate/src/getLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,34 @@ import { BatchDelegateOptions } from './types';

const cache1: WeakMap<
ReadonlyArray<FieldNode>,
WeakMap<GraphQLSchema | SubschemaConfig, Record<string, DataLoader<any, any>>>
WeakMap<GraphQLSchema | SubschemaConfig<any, any, any, any>, Record<string, DataLoader<any, any>>>
> = new WeakMap();

function createBatchFn<K = any>(options: BatchDelegateOptions) {
const argsFromKeys = options.argsFromKeys ?? ((keys: ReadonlyArray<K>) => ({ ids: keys }));
const fieldName = options.fieldName ?? options.info.fieldName;
const { valuesFromResults, lazyOptionsFn } = options;

return async (keys: ReadonlyArray<K>) => {
const results = await delegateToSchema({
returnType: new GraphQLList(getNamedType(options.info.returnType) as GraphQLOutputType),
onLocatedError: originalError =>
relocatedError(originalError, originalError.path.slice(0, 0).concat(originalError.path.slice(2))),
onLocatedError: originalError => {
if (originalError.path == null) {
return originalError;
}

const [pathFieldName, pathNumber] = originalError.path;

if (pathFieldName !== fieldName) {
throw new Error(`Error path value at index 0 should be '${fieldName}', received '${pathFieldName}'.`);
}
const pathNumberType = typeof pathNumber;
if (pathNumberType !== 'number') {
throw new Error(`Error path value at index 1 should be of type number, received '${pathNumberType}'.`);
}

return relocatedError(originalError, originalError.path.slice(0, 0).concat(originalError.path.slice(2)));
},
args: argsFromKeys(keys),
...(lazyOptionsFn == null ? options : lazyOptionsFn(options)),
});
Expand All @@ -35,10 +51,10 @@ function createBatchFn<K = any>(options: BatchDelegateOptions) {
};
}

export function getLoader<K = any, V = any, C = K>(options: BatchDelegateOptions): DataLoader<K, V, C> {
export function getLoader<K = any, V = any, C = K>(options: BatchDelegateOptions<any>): DataLoader<K, V, C> {
const fieldName = options.fieldName ?? options.info.fieldName;

let cache2: WeakMap<GraphQLSchema | SubschemaConfig, Record<string, DataLoader<K, V, C>>> = cache1.get(
let cache2: WeakMap<GraphQLSchema | SubschemaConfig, Record<string, DataLoader<K, V, C>>> | undefined = cache1.get(
options.info.fieldNodes
);

Expand All @@ -56,7 +72,7 @@ export function getLoader<K = any, V = any, C = K>(options: BatchDelegateOptions
let loaders = cache2.get(options.schema);

if (loaders === undefined) {
loaders = Object.create(null);
loaders = Object.create(null) as Record<string, DataLoader<K, V, C>>;
cache2.set(options.schema, loaders);
const batchFn = createBatchFn(options);
const loader = new DataLoader<K, V, C>(keys => batchFn(keys), options.dataLoaderOptions);
Expand Down
10 changes: 5 additions & 5 deletions packages/batch-delegate/tests/basic.example.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describe('batch delegation within basic stitching example', () => {

expect(numCalls).toEqual(1);
expect(result.errors).toBeUndefined();
expect(result.data.trendingChirps[0].chirpedAtUser.email).not.toBe(null);
expect(result.data!.trendingChirps[0].chirpedAtUser.email).not.toBe(null);
});

test('works with key arrays', async () => {
Expand All @@ -108,9 +108,9 @@ describe('batch delegation within basic stitching example', () => {
`,
resolvers: {
Query: {
posts: (obj, args) => {
posts: (_, args) => {
numCalls += 1;
return args.ids.map(id => ({ id, title: `Post ${id}` }));
return args.ids.map((id: unknown) => ({ id, title: `Post ${id}` }));
}
}
}
Expand All @@ -129,8 +129,8 @@ describe('batch delegation within basic stitching example', () => {
`,
resolvers: {
Query: {
users: (obj, args) => {
return args.ids.map(id => {
users: (_, args) => {
return args.ids.map((id: unknown) => {
return { id, postIds: [Number(id)+1, Number(id)+2] };
});
}
Expand Down
2 changes: 1 addition & 1 deletion packages/batch-delegate/tests/withTransforms.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ describe('works with complex transforms', () => {
context,
info,
transforms: [queryTransform],
returnType: new GraphQLList(new GraphQLList(info.schema.getType('Book')))
returnType: new GraphQLList(new GraphQLList(info.schema.getType('Book')!))
}),
},
},
Expand Down
43 changes: 27 additions & 16 deletions packages/batch-execute/src/createBatchingExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,37 @@ import { splitResult } from './splitResult';
export function createBatchingExecutor(
executor: Executor,
dataLoaderOptions?: DataLoader.Options<any, any, any>,
extensionsReducer?: (mergedExtensions: Record<string, any>, executionParams: ExecutionParams) => Record<string, any>
extensionsReducer: (
mergedExtensions: Record<string, any>,
executionParams: ExecutionParams
) => Record<string, any> = defaultExtensionsReducer
): Executor {
const loader = new DataLoader(
createLoadFn(executor, extensionsReducer ?? defaultExtensionsReducer),
dataLoaderOptions
);
const loader = new DataLoader(createLoadFn(executor, extensionsReducer), dataLoaderOptions);
return (executionParams: ExecutionParams) => loader.load(executionParams);
}

function createLoadFn(
executor: ({ document, context, variables, info }: ExecutionParams) => ExecutionResult | Promise<ExecutionResult>,
executor: Executor,
extensionsReducer: (mergedExtensions: Record<string, any>, executionParams: ExecutionParams) => Record<string, any>
) {
return async (execs: Array<ExecutionParams>): Promise<Array<ExecutionResult>> => {
return async (execs: ReadonlyArray<ExecutionParams>): Promise<Array<ExecutionResult>> => {
const execBatches: Array<Array<ExecutionParams>> = [];
let index = 0;
const exec = execs[index];
let currentBatch: Array<ExecutionParams> = [exec];
execBatches.push(currentBatch);
const operationType = getOperationAST(exec.document, undefined).operation;

const operationType = getOperationAST(exec.document, undefined)?.operation;
if (operationType == null) {
throw new Error('Could not identify operation type of document.');
}

while (++index < execs.length) {
const currentOperationType = getOperationAST(execs[index].document, undefined).operation;
const currentOperationType = getOperationAST(execs[index].document, undefined)?.operation;
if (operationType == null) {
throw new Error('Could not identify operation type of document.');
}

if (operationType === currentOperationType) {
currentBatch.push(execs[index]);
} else {
Expand All @@ -48,13 +57,15 @@ function createLoadFn(
executionResults.push(new ValueOrPromise(() => executor(mergedExecutionParams)));
});

return ValueOrPromise.all(executionResults).then(resultBatches => {
let results: Array<ExecutionResult> = [];
resultBatches.forEach((resultBatch, index) => {
results = results.concat(splitResult(resultBatch, execBatches[index].length));
});
return results;
}).resolve();
return ValueOrPromise.all(executionResults)
.then(resultBatches => {
let results: Array<ExecutionResult> = [];
resultBatches.forEach((resultBatch, index) => {
results = [...results, ...splitResult(resultBatch!, execBatches[index].length)];
});
return results;
})
.resolve();
};
}

Expand Down
6 changes: 4 additions & 2 deletions packages/batch-execute/src/getBatchingExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import { memoize2of4 } from './memoize';
export const getBatchingExecutor = memoize2of4(function (
_context: Record<string, any> = self ?? window ?? global,
executor: Executor,
dataLoaderOptions?: DataLoader.Options<any, any, any>,
extensionsReducer?: (mergedExtensions: Record<string, any>, executionParams: ExecutionParams) => Record<string, any>
dataLoaderOptions?: DataLoader.Options<any, any, any> | undefined,
extensionsReducer?:
| undefined
| ((mergedExtensions: Record<string, any>, executionParams: ExecutionParams) => Record<string, any>)
): Executor {
return createBatchingExecutor(executor, dataLoaderOptions, extensionsReducer);
});
17 changes: 11 additions & 6 deletions packages/batch-execute/src/mergeExecutionParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
OperationTypeNode,
} from 'graphql';

import { ExecutionParams } from '@graphql-tools/utils';
import { ExecutionParams, Maybe } from '@graphql-tools/utils';

import { createPrefix } from './prefix';

Expand Down Expand Up @@ -66,7 +66,7 @@ export function mergeExecutionParams(
const mergedFragmentDefinitions: Array<FragmentDefinitionNode> = [];
let mergedExtensions: Record<string, any> = Object.create(null);

let operation: OperationTypeNode;
let operation: Maybe<OperationTypeNode>;

execs.forEach((executionParams, index) => {
const prefixedExecutionParams = prefixExecutionParams(createPrefix(index), executionParams);
Expand All @@ -85,6 +85,10 @@ export function mergeExecutionParams(
mergedExtensions = extensionsReducer(mergedExtensions, executionParams);
});

if (operation == null) {
throw new Error('Could not identify operation type. Did the document only include fragment definitions?');
}

const mergedOperationDefinition: OperationDefinitionNode = {
kind: Kind.OPERATION_DEFINITION,
operation,
Expand All @@ -109,7 +113,8 @@ export function mergeExecutionParams(

function prefixExecutionParams(prefix: string, executionParams: ExecutionParams): ExecutionParams {
let document = aliasTopLevelFields(prefix, executionParams.document);
const variableNames = Object.keys(executionParams.variables);
const executionVariables = executionParams.variables ?? {};
const variableNames = Object.keys(executionVariables);

if (variableNames.length === 0) {
return { ...executionParams, document };
Expand All @@ -122,7 +127,7 @@ function prefixExecutionParams(prefix: string, executionParams: ExecutionParams)
});

const prefixedVariables = variableNames.reduce((acc, name) => {
acc[prefix + name] = executionParams.variables[name];
acc[prefix + name] = executionVariables[name];
return acc;
}, Object.create(null));

Expand Down Expand Up @@ -150,9 +155,9 @@ function aliasTopLevelFields(prefix: string, document: DocumentNode): DocumentNo
};
},
};
return visit(document, transformer, ({
return visit(document, transformer, {
[Kind.DOCUMENT]: [`definitions`],
} as unknown) as VisitorKeyMap<ASTKindToNode>);
} as unknown as VisitorKeyMap<ASTKindToNode>);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/batch-execute/src/prefix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export function createPrefix(index: number): string {
return `graphqlTools${index}_`;
}

export function parseKey(prefixedKey: string): { index: number; originalKey: string } {
export function parseKey(prefixedKey: string): null | { index: number; originalKey: string } {
const match = /^graphqlTools([\d]+)_(.*)$/.exec(prefixedKey);
if (match && match.length === 3 && !isNaN(Number(match[1])) && match[2]) {
return { index: Number(match[1]), originalKey: match[2] };
Expand Down
16 changes: 11 additions & 5 deletions packages/batch-execute/src/splitResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { ExecutionResult, GraphQLError } from 'graphql';

import { relocatedError } from '@graphql-tools/utils';
import { assertSome, relocatedError } from '@graphql-tools/utils';

import { parseKey } from './prefix';

Expand All @@ -18,11 +18,17 @@ export function splitResult(mergedResult: ExecutionResult, numResults: number):
const data = mergedResult.data;
if (data) {
Object.keys(data).forEach(prefixedKey => {
const { index, originalKey } = parseKey(prefixedKey);
if (!splitResults[index].data) {
splitResults[index].data = { [originalKey]: data[prefixedKey] };
const parsedKey = parseKey(prefixedKey);
assertSome(parsedKey, "'parsedKey' should not be null.");
const { index, originalKey } = parsedKey;
const result = splitResults[index];
if (result == null) {
return;
}
if (result.data == null) {
result.data = { [originalKey]: data[prefixedKey] };
} else {
splitResults[index].data[originalKey] = data[prefixedKey];
result.data[originalKey] = data[prefixedKey];
}
});
}
Expand Down
5 changes: 3 additions & 2 deletions packages/delegate/src/Subschema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ interface ISubschema<K = any, V = any, C = K, TContext = Record<string, any>>
}

export class Subschema<K = any, V = any, C = K, TContext = Record<string, any>>
implements ISubschema<K, V, C, TContext> {
implements ISubschema<K, V, C, TContext>
{
public schema: GraphQLSchema;

public rootValue?: Record<string, any>;
Expand All @@ -25,7 +26,7 @@ export class Subschema<K = any, V = any, C = K, TContext = Record<string, any>>
public batchingOptions?: BatchingOptions<K, V, C>;

public createProxyingResolver?: CreateProxyingResolverFn<TContext>;
public transforms: Array<Transform>;
public transforms: Array<Transform<any, TContext>>;
public transformedSchema: GraphQLSchema;

public merge?: Record<string, MergedTypeConfig<any, any, TContext>>;
Expand Down
6 changes: 3 additions & 3 deletions packages/delegate/src/Transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ interface Transformation {
context: Record<string, any>;
}

export class Transformer {
export class Transformer<TContext = Record<string, any>> {
private transformations: Array<Transformation> = [];
private delegationContext: DelegationContext;
private delegationContext: DelegationContext<any>;

constructor(context: DelegationContext, binding: DelegationBinding = defaultDelegationBinding) {
constructor(context: DelegationContext<TContext>, binding: DelegationBinding<TContext> = defaultDelegationBinding) {
this.delegationContext = context;
const delegationTransforms: Array<Transform> = binding(this.delegationContext);
delegationTransforms.forEach(transform => this.addTransform(transform, {}));
Expand Down
6 changes: 3 additions & 3 deletions packages/delegate/src/applySchemaTransforms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { GraphQLSchema } from 'graphql';

import { cloneSchema } from '@graphql-tools/utils';

import { SubschemaConfig, Transform } from './types';
import { SubschemaConfig } from './types';

export function applySchemaTransforms(
originalWrappingSchema: GraphQLSchema,
subschemaConfig: SubschemaConfig,
subschemaConfig: SubschemaConfig<any, any, any, any>,
transformedSchema?: GraphQLSchema
): GraphQLSchema {
const schemaTransforms = subschemaConfig.transforms;
Expand All @@ -16,7 +16,7 @@ export function applySchemaTransforms(
}

return schemaTransforms.reduce(
(schema: GraphQLSchema, transform: Transform) =>
(schema: GraphQLSchema, transform) =>
transform.transformSchema != null
? transform.transformSchema(cloneSchema(schema), subschemaConfig, transformedSchema)
: schema,
Expand Down
Loading

0 comments on commit 806faae

Please sign in to comment.