Skip to content

Commit

Permalink
enable strictNullChecks 17 stitch
Browse files Browse the repository at this point in the history
  • Loading branch information
n1ru4l committed Jun 3, 2021
1 parent a1d6c62 commit 74b0da3
Show file tree
Hide file tree
Showing 32 changed files with 299 additions and 188 deletions.
4 changes: 2 additions & 2 deletions packages/delegate/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,9 @@ export type MergedTypeResolver<TContext = Record<string, any>> = (

export interface StitchingInfo<TContext = Record<string, any>> {
subschemaMap: Map<GraphQLSchema | SubschemaConfig<any, any, any, TContext>, Subschema<any, any, any, TContext>>;
selectionSetsByType: Record<string, SelectionSetNode>;
selectionSetsByType: Record<string, SelectionSetNode> | undefined;
selectionSetsByField: Record<string, Record<string, SelectionSetNode>>;
dynamicSelectionSetsByField: Record<string, Record<string, Array<(node: FieldNode) => SelectionSetNode>>>;
dynamicSelectionSetsByField: Record<string, Record<string, Array<(node: FieldNode) => SelectionSetNode>>> | undefined;
mergedTypes: Record<string, MergedTypeInfo<TContext>>;
}

Expand Down
4 changes: 3 additions & 1 deletion packages/stitch/src/createMergedTypeResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { getNamedType, GraphQLOutputType, GraphQLList } from 'graphql';
import { delegateToSchema, MergedTypeResolver, MergedTypeResolverOptions } from '@graphql-tools/delegate';
import { batchDelegateToSchema } from '@graphql-tools/batch-delegate';

export function createMergedTypeResolver(mergedTypeResolverOptions: MergedTypeResolverOptions): MergedTypeResolver {
export function createMergedTypeResolver(
mergedTypeResolverOptions: MergedTypeResolverOptions
): MergedTypeResolver | undefined {
const { fieldName, argsFromKeys, valuesFromResults, args } = mergedTypeResolverOptions;

if (argsFromKeys != null) {
Expand Down
62 changes: 34 additions & 28 deletions packages/stitch/src/mergeCandidates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ import {
GraphQLScalarSerializer,
GraphQLScalarValueParser,
GraphQLScalarLiteralParser,
ObjectTypeExtensionNode,
InputObjectTypeExtensionNode,
InterfaceTypeExtensionNode,
UnionTypeExtensionNode,
EnumTypeExtensionNode,
ScalarTypeExtensionNode,
} from 'graphql';

import { mergeType, mergeInputType, mergeInterface, mergeUnion, mergeEnum, mergeScalar } from '@graphql-tools/merge';
Expand All @@ -44,13 +50,13 @@ import {
validateInputObjectConsistency,
} from './mergeValidations';

import { fieldToFieldConfig, inputFieldToFieldConfig } from '@graphql-tools/utils';
import { fieldToFieldConfig, inputFieldToFieldConfig, Maybe } from '@graphql-tools/utils';
import { isSubschemaConfig } from '@graphql-tools/delegate';

export function mergeCandidates<TContext = Record<string, any>>(
typeName: string,
candidates: Array<MergeTypeCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): GraphQLNamedType {
const initialCandidateType = candidates[0].type;
if (candidates.some(candidate => candidate.type.constructor !== initialCandidateType.constructor)) {
Expand All @@ -77,7 +83,7 @@ export function mergeCandidates<TContext = Record<string, any>>(
function mergeObjectTypeCandidates<TContext = Record<string, any>>(
typeName: string,
candidates: Array<MergeTypeCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): GraphQLObjectType<any, any> {
candidates = orderedTypeCandidates(candidates, typeMergingOptions);

Expand Down Expand Up @@ -116,7 +122,7 @@ function mergeObjectTypeCandidates<TContext = Record<string, any>>(
astNodes[0]
);

const extensionASTNodes = [].concat(pluck<Record<string, any>>('extensionASTNodes', candidates));
const extensionASTNodes = pluck<ObjectTypeExtensionNode>('extensionASTNodes', candidates);

const extensions = Object.assign({}, ...pluck<Record<string, any>>('extensions', candidates));

Expand All @@ -136,7 +142,7 @@ function mergeObjectTypeCandidates<TContext = Record<string, any>>(
function mergeInputObjectTypeCandidates<TContext = Record<string, any>>(
typeName: string,
candidates: Array<MergeTypeCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): GraphQLInputObjectType {
candidates = orderedTypeCandidates(candidates, typeMergingOptions);

Expand All @@ -163,7 +169,7 @@ function mergeInputObjectTypeCandidates<TContext = Record<string, any>>(
astNodes[0]
);

const extensionASTNodes = [].concat(pluck<Record<string, any>>('extensionASTNodes', candidates));
const extensionASTNodes = pluck<InputObjectTypeExtensionNode>('extensionASTNodes', candidates);

const extensions = Object.assign({}, ...pluck<Record<string, any>>('extensions', candidates));

Expand All @@ -186,7 +192,7 @@ function pluck<T>(typeProperty: string, candidates: Array<MergeTypeCandidate<any
function mergeInterfaceTypeCandidates<TContext = Record<string, any>>(
typeName: string,
candidates: Array<MergeTypeCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): GraphQLInterfaceType {
candidates = orderedTypeCandidates(candidates, typeMergingOptions);

Expand Down Expand Up @@ -225,7 +231,7 @@ function mergeInterfaceTypeCandidates<TContext = Record<string, any>>(
astNodes[0]
);

const extensionASTNodes = [].concat(pluck<Record<string, any>>('extensionASTNodes', candidates));
const extensionASTNodes = pluck<InterfaceTypeExtensionNode>('extensionASTNodes', candidates);

const extensions = Object.assign({}, ...pluck<Record<string, any>>('extensions', candidates));

Expand All @@ -245,7 +251,7 @@ function mergeInterfaceTypeCandidates<TContext = Record<string, any>>(
function mergeUnionTypeCandidates<TContext = Record<string, any>>(
typeName: string,
candidates: Array<MergeTypeCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): GraphQLUnionType {
candidates = orderedTypeCandidates(candidates, typeMergingOptions);
const description = mergeTypeDescriptions(candidates, typeMergingOptions);
Expand All @@ -267,7 +273,7 @@ function mergeUnionTypeCandidates<TContext = Record<string, any>>(
astNodes[0]
);

const extensionASTNodes = [].concat(pluck<Record<string, any>>('extensionASTNodes', candidates));
const extensionASTNodes = pluck<UnionTypeExtensionNode>('extensionASTNodes', candidates);

const extensions = Object.assign({}, ...pluck<Record<string, any>>('extensions', candidates));

Expand All @@ -286,7 +292,7 @@ function mergeUnionTypeCandidates<TContext = Record<string, any>>(
function mergeEnumTypeCandidates<TContext = Record<string, any>>(
typeName: string,
candidates: Array<MergeTypeCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): GraphQLEnumType {
candidates = orderedTypeCandidates(candidates, typeMergingOptions);

Expand All @@ -302,7 +308,7 @@ function mergeEnumTypeCandidates<TContext = Record<string, any>>(
astNodes[0]
);

const extensionASTNodes = [].concat(pluck<Record<string, any>>('extensionASTNodes', candidates));
const extensionASTNodes = pluck<EnumTypeExtensionNode>('extensionASTNodes', candidates);

const extensions = Object.assign({}, ...pluck<Record<string, any>>('extensions', candidates));

Expand All @@ -320,7 +326,7 @@ function mergeEnumTypeCandidates<TContext = Record<string, any>>(

function enumValueConfigMapFromTypeCandidates(
candidates: Array<MergeTypeCandidate<any>>,
typeMergingOptions: TypeMergingOptions<any>
typeMergingOptions?: TypeMergingOptions<any>
): GraphQLEnumValueConfigMap {
const enumValueConfigCandidatesMap: Record<string, Array<MergeEnumValueConfigCandidate>> = Object.create(null);

Expand Down Expand Up @@ -364,7 +370,7 @@ function defaultEnumValueConfigMerger(candidates: Array<MergeEnumValueConfigCand
function mergeScalarTypeCandidates<TContext = Record<string, any>>(
typeName: string,
candidates: Array<MergeTypeCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): GraphQLScalarType {
candidates = orderedTypeCandidates(candidates, typeMergingOptions);

Expand All @@ -386,7 +392,7 @@ function mergeScalarTypeCandidates<TContext = Record<string, any>>(
astNodes[0]
);

const extensionASTNodes = [].concat(pluck<Record<string, any>>('extensionASTNodes', candidates));
const extensionASTNodes = pluck<ScalarTypeExtensionNode>('extensionASTNodes', candidates);

const extensions = Object.assign({}, ...pluck<Record<string, any>>('extensions', candidates));

Expand All @@ -406,7 +412,7 @@ function mergeScalarTypeCandidates<TContext = Record<string, any>>(

function orderedTypeCandidates<TContext = Record<string, any>>(
candidates: Array<MergeTypeCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): Array<MergeTypeCandidate<TContext>> {
const typeCandidateMerger = typeMergingOptions?.typeCandidateMerger ?? defaultTypeCandidateMerger;
const candidate = typeCandidateMerger(candidates);
Expand All @@ -431,21 +437,21 @@ function defaultTypeCandidateMerger<TContext = Record<string, any>>(

function mergeTypeDescriptions<TContext = Record<string, any>>(
candidates: Array<MergeTypeCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
): string {
typeMergingOptions?: TypeMergingOptions<TContext>
): Maybe<string> {
const typeDescriptionsMerger = typeMergingOptions?.typeDescriptionsMerger ?? defaultTypeDescriptionMerger;
return typeDescriptionsMerger(candidates);
}

function defaultTypeDescriptionMerger<TContext = Record<string, any>>(
candidates: Array<MergeTypeCandidate<TContext>>
): string {
): Maybe<string> {
return candidates[candidates.length - 1].type.description;
}

function fieldConfigMapFromTypeCandidates<TContext = Record<string, any>>(
candidates: Array<MergeTypeCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): GraphQLFieldConfigMap<any, any> {
const fieldConfigCandidatesMap: Record<string, Array<MergeFieldConfigCandidate<TContext>>> = Object.create(null);

Expand Down Expand Up @@ -479,7 +485,7 @@ function fieldConfigMapFromTypeCandidates<TContext = Record<string, any>>(

function mergeFieldConfigs<TContext = Record<string, any>>(
candidates: Array<MergeFieldConfigCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
) {
const fieldConfigMerger = typeMergingOptions?.fieldConfigMerger ?? defaultFieldConfigMerger;
const finalFieldConfig = fieldConfigMerger(candidates);
Expand Down Expand Up @@ -515,7 +521,7 @@ function defaultFieldConfigMerger<TContext = Record<string, any>>(

function inputFieldConfigMapFromTypeCandidates<TContext = Record<string, any>>(
candidates: Array<MergeTypeCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): GraphQLInputFieldConfigMap {
const inputFieldConfigCandidatesMap: Record<string, Array<MergeInputFieldConfigCandidate<TContext>>> =
Object.create(null);
Expand Down Expand Up @@ -590,12 +596,12 @@ function canonicalFieldNamesForType<TContext>(candidates: Array<MergeTypeCandida
const canonicalFieldNames: Record<string, boolean> = Object.create(null);

candidates.forEach(({ type, transformedSubschema }) => {
if (
isSubschemaConfig(transformedSubschema) &&
transformedSubschema.merge?.[type.name]?.fields &&
!transformedSubschema.merge[type.name].canonical
) {
Object.entries(transformedSubschema.merge[type.name].fields).forEach(([fieldName, mergedFieldConfig]) => {
if (!isSubschemaConfig(transformedSubschema)) {
return;
}
const mergeConfig = transformedSubschema.merge?.[type.name];
if (mergeConfig != null && mergeConfig.fields != null && !mergeConfig.canonical) {
Object.entries(mergeConfig.fields).forEach(([fieldName, mergedFieldConfig]) => {
if (mergedFieldConfig.canonical) {
canonicalFieldNames[fieldName] = true;
}
Expand Down
20 changes: 13 additions & 7 deletions packages/stitch/src/mergeValidations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
export function validateFieldConsistency<TContext = Record<string, any>>(
finalFieldConfig: GraphQLFieldConfig<any, any>,
candidates: Array<MergeFieldConfigCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): void {
const fieldNamespace = `${candidates[0].type.name}.${candidates[0].fieldName}`;
const finalFieldNull = isNonNullType(finalFieldConfig.type);
Expand Down Expand Up @@ -56,6 +56,9 @@ export function validateFieldConsistency<TContext = Record<string, any>>(

const argCandidatesMap: Record<string, Array<GraphQLArgumentConfig>> = Object.create(null);
candidates.forEach(({ fieldConfig }) => {
if (fieldConfig.args == null) {
return;
}
Object.entries(fieldConfig.args).forEach(([argName, arg]) => {
argCandidatesMap[argName] = argCandidatesMap[argName] || [];
argCandidatesMap[argName].push(arg);
Expand All @@ -71,6 +74,9 @@ export function validateFieldConsistency<TContext = Record<string, any>>(
}

Object.entries(argCandidatesMap).forEach(([argName, argCandidates]) => {
if (finalFieldConfig.args == null) {
return;
}
const argNamespace = `${fieldNamespace}.${argName}`;
const finalArgConfig = finalFieldConfig.args[argName] || argCandidates[argCandidates.length - 1];
const finalArgType = getNamedType(finalArgConfig.type);
Expand Down Expand Up @@ -104,7 +110,7 @@ export function validateFieldConsistency<TContext = Record<string, any>>(
export function validateInputObjectConsistency<TContext = Record<string, any>>(
fieldInclusionMap: Record<string, number>,
candidates: Array<MergeTypeCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): void {
Object.entries(fieldInclusionMap).forEach(([fieldName, count]) => {
if (candidates.length !== count) {
Expand All @@ -121,7 +127,7 @@ export function validateInputObjectConsistency<TContext = Record<string, any>>(
export function validateInputFieldConsistency<TContext = Record<string, any>>(
finalInputFieldConfig: GraphQLInputFieldConfig,
candidates: Array<MergeInputFieldConfigCandidate<TContext>>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): void {
const inputFieldNamespace = `${candidates[0].type.name}.${candidates[0].fieldName}`;
const inputFieldConfigs = candidates.map(c => c.inputFieldConfig);
Expand Down Expand Up @@ -163,7 +169,7 @@ export function validateTypeConsistency<TContext = Record<string, any>>(
candidates: Array<GraphQLFieldConfig<any, any> | GraphQLArgumentConfig | GraphQLInputFieldConfig>,
definitionType: string,
settingNamespace: string,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): void {
const finalNamedType = getNamedType(finalElementConfig.type);
const finalIsScalar = isScalarType(finalNamedType);
Expand Down Expand Up @@ -205,7 +211,7 @@ function hasListType(type: GraphQLType): boolean {
export function validateInputEnumConsistency<TContext = Record<string, any>>(
inputEnumType: GraphQLEnumType,
candidates: Array<GraphQLArgumentConfig | GraphQLInputFieldConfig>,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): void {
const enumValueInclusionMap: Record<string, number> = Object.create(null);

Expand All @@ -231,7 +237,7 @@ export function validateInputEnumConsistency<TContext = Record<string, any>>(
function validationMessage<TContext = Record<string, any>>(
message: string,
settingNamespace: string,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): void {
const override = `typeMergingOptions.validationScopes['${settingNamespace}'].validationLevel`;
const settings = getValidationSettings(settingNamespace, typeMergingOptions);
Expand All @@ -250,7 +256,7 @@ function validationMessage<TContext = Record<string, any>>(

function getValidationSettings<TContext = Record<string, any>>(
settingNamespace: string,
typeMergingOptions: TypeMergingOptions<TContext>
typeMergingOptions?: TypeMergingOptions<TContext>
): ValidationSettings {
return {
...(typeMergingOptions?.validationSettings ?? {}),
Expand Down
26 changes: 12 additions & 14 deletions packages/stitch/src/selectionSetArgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,20 @@ export const forwardArgsToSelectionSet: (
) => (field: FieldNode) => SelectionSetNode = (selectionSet: string, mapping?: Record<string, string[]>) => {
const selectionSetDef = parseSelectionSet(selectionSet, { noLocation: true });
return (field: FieldNode): SelectionSetNode => {
const selections = selectionSetDef.selections.map(
(selectionNode): SelectionNode => {
if (selectionNode.kind === Kind.FIELD) {
if (!mapping) {
return { ...selectionNode, arguments: field.arguments.slice() };
} else if (selectionNode.name.value in mapping) {
const selectionArgs = mapping[selectionNode.name.value];
return {
...selectionNode,
arguments: field.arguments.filter((arg): boolean => selectionArgs.includes(arg.name.value)),
};
}
const selections = selectionSetDef.selections.map((selectionNode): SelectionNode => {
if (selectionNode.kind === Kind.FIELD) {
if (!mapping) {
return { ...selectionNode, arguments: field.arguments?.slice() };
} else if (selectionNode.name.value in mapping) {
const selectionArgs = mapping[selectionNode.name.value];
return {
...selectionNode,
arguments: field.arguments?.filter((arg): boolean => selectionArgs.includes(arg.name.value)),
};
}
return selectionNode;
}
);
return selectionNode;
});

return { ...selectionSetDef, selections };
};
Expand Down
14 changes: 8 additions & 6 deletions packages/stitch/src/stitchingInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
isLeafType,
} from 'graphql';

import { parseSelectionSet, TypeMap, IResolvers, IFieldResolverOptions } from '@graphql-tools/utils';
import { parseSelectionSet, TypeMap, IResolvers, IFieldResolverOptions, isSome } from '@graphql-tools/utils';

import { MergedTypeResolver, Subschema, SubschemaConfig, MergedTypeInfo, StitchingInfo } from '@graphql-tools/delegate';

Expand Down Expand Up @@ -136,12 +136,14 @@ function createMergedTypes<TContext = Record<string, any>>(

if (mergedTypeConfig.fields) {
const parsedFieldSelectionSets = Object.create(null);
Object.keys(mergedTypeConfig.fields).forEach(fieldName => {
for (const fieldName in mergedTypeConfig.fields) {
if (mergedTypeConfig.fields[fieldName].selectionSet) {
const rawFieldSelectionSet = mergedTypeConfig.fields[fieldName].selectionSet;
parsedFieldSelectionSets[fieldName] = parseSelectionSet(rawFieldSelectionSet, { noLocation: true });
parsedFieldSelectionSets[fieldName] = rawFieldSelectionSet
? parseSelectionSet(rawFieldSelectionSet, { noLocation: true })
: undefined;
}
});
}
fieldSelectionSets.set(subschema, parsedFieldSelectionSets);
}

Expand Down Expand Up @@ -181,8 +183,8 @@ function createMergedTypes<TContext = Record<string, any>>(
});

const sourceSubschemas = typeCandidates[typeName]
.filter(typeCandidate => typeCandidate.transformedSubschema != null)
.map(typeCandidate => typeCandidate.transformedSubschema);
.map(typeCandidate => typeCandidate?.transformedSubschema)
.filter(isSome);
const targetSubschemasBySubschema: Map<
Subschema<any, any, any, TContext>,
Array<Subschema<any, any, any, TContext>>
Expand Down
Loading

0 comments on commit 74b0da3

Please sign in to comment.