From 1d2338cc4800d8e3c11c5160b99a59b20f736140 Mon Sep 17 00:00:00 2001 From: Saihajpreet Singh Date: Wed, 18 Nov 2020 09:43:23 -0600 Subject: [PATCH 1/8] run @khanacademy/flow-to-ts --- .../{dedent-test.js => dedent-test.ts} | 0 ...Strings-test.js => genFuzzStrings-test.ts} | 8 +- ...{inspectStr-test.js => inspectStr-test.ts} | 0 ...Tick-test.js => resolveOnNextTick-test.ts} | 0 src/__testUtils__/{dedent.js => dedent.ts} | 4 +- .../{genFuzzStrings.js => genFuzzStrings.ts} | 8 +- .../{inspectStr.js => inspectStr.ts} | 2 +- ...itchenSinkQuery.js => kitchenSinkQuery.ts} | 1 - .../{kitchenSinkSDL.js => kitchenSinkSDL.ts} | 0 ...olveOnNextTick.js => resolveOnNextTick.ts} | 0 .../{starWarsData.js => starWarsData.ts} | 52 +- ...-test.js => starWarsIntrospection-test.ts} | 0 ...arsQuery-test.js => starWarsQuery-test.ts} | 0 .../{starWarsSchema.js => starWarsSchema.ts} | 0 ...ion-test.js => starWarsValidation-test.ts} | 0 .../{version-test.js => version-test.ts} | 3 +- .../{GraphQLError.js => GraphQLError.ts} | 76 +- ...phQLError-test.js => GraphQLError-test.ts} | 0 ...ormatError-test.js => formatError-test.ts} | 0 ...atedError-test.js => locatedError-test.ts} | 14 +- src/error/{formatError.js => formatError.ts} | 21 +- src/error/{index.js => index.ts} | 2 +- .../{locatedError.js => locatedError.ts} | 16 +- src/error/{syntaxError.js => syntaxError.ts} | 2 +- .../{abstract-test.js => abstract-test.ts} | 16 +- ...{directives-test.js => directives-test.ts} | 0 .../{executor-test.js => executor-test.ts} | 2 +- .../{lists-test.js => lists-test.ts} | 8 +- .../{mutations-test.js => mutations-test.ts} | 0 .../{nonnull-test.js => nonnull-test.ts} | 6 +- .../{resolve-test.js => resolve-test.ts} | 6 +- .../{schema-test.js => schema-test.ts} | 0 .../__tests__/{sync-test.js => sync-test.ts} | 0 ...erface-test.js => union-interface-test.ts} | 0 .../{variables-test.js => variables-test.ts} | 6 +- src/execution/{execute.js => execute.ts} | 203 ++- src/execution/{index.js => index.ts} | 2 +- src/execution/{values.js => values.ts} | 56 +- src/{graphql.js => graphql.ts} | 38 +- src/{index.js => index.ts} | 157 +- src/jsutils/ObjMap.js | 7 - src/jsutils/ObjMap.ts | 13 + src/jsutils/{Path.js => Path.ts} | 15 +- src/jsutils/PromiseOrValue.js | 1 - src/jsutils/PromiseOrValue.ts | 1 + ...{didYouMean-test.js => didYouMean-test.ts} | 0 ...ntityFunc-test.js => identityFunc-test.ts} | 0 .../{inspect-test.js => inspect-test.ts} | 2 +- ...{instanceOf-test.js => instanceOf-test.ts} | 0 .../{invariant-test.js => invariant-test.ts} | 0 ...erable-test.js => isAsyncIterable-test.ts} | 0 ...ollection-test.js => isCollection-test.ts} | 0 ...bjectLike-test.js => isObjectLike-test.ts} | 0 ...ionList-test.js => suggestionList-test.ts} | 0 .../{toObjMap-test.js => toObjMap-test.ts} | 2 +- src/jsutils/{devAssert.js => devAssert.ts} | 2 +- src/jsutils/{didYouMean.js => didYouMean.ts} | 4 +- .../{identityFunc.js => identityFunc.ts} | 0 src/jsutils/{inspect.js => inspect.ts} | 14 +- src/jsutils/{instanceOf.js => instanceOf.ts} | 23 +- src/jsutils/{invariant.js => invariant.ts} | 2 +- ...{isAsyncIterable.js => isAsyncIterable.ts} | 3 +- .../{isCollection.js => isCollection.ts} | 3 +- .../{isObjectLike.js => isObjectLike.ts} | 2 +- src/jsutils/{isPromise.js => isPromise.ts} | 3 +- src/jsutils/{keyMap.js => keyMap.ts} | 4 +- src/jsutils/{keyValMap.js => keyValMap.ts} | 4 +- src/jsutils/{mapValue.js => mapValue.ts} | 2 +- src/jsutils/{memoize3.js => memoize3.ts} | 12 +- .../{printPathArray.js => printPathArray.ts} | 2 +- ...romiseForObject.js => promiseForObject.ts} | 2 +- .../{promiseReduce.js => promiseReduce.ts} | 6 +- .../{suggestionList.js => suggestionList.ts} | 2 +- src/jsutils/{toObjMap.js => toObjMap.ts} | 2 +- ...lockString-fuzz.js => blockString-fuzz.ts} | 0 ...lockString-test.js => blockString-test.ts} | 0 .../{lexer-test.js => lexer-test.ts} | 0 .../{parser-test.js => parser-test.ts} | 0 ...{predicates-test.js => predicates-test.ts} | 6 +- ...Location-test.js => printLocation-test.ts} | 0 .../{printer-test.js => printer-test.ts} | 12 +- ...a-parser-test.js => schema-parser-test.ts} | 23 +- ...printer-test.js => schema-printer-test.ts} | 0 .../{source-test.js => source-test.ts} | 2 +- .../{toJSONDeep.js => toJSONDeep.ts} | 2 +- .../{visitor-test.js => visitor-test.ts} | 55 +- src/language/ast.js | 640 ------- src/language/ast.ts | 560 ++++++ .../{blockString.js => blockString.ts} | 17 +- ...ectiveLocation.js => directiveLocation.ts} | 2 + .../{grammar.js => grammar.ts} | 20 +- .../{index.js => index.ts} | 0 .../{onlineParser.js => onlineParser.ts} | 82 +- src/language/{index.js => index.ts} | 17 +- src/language/{kinds.js => kinds.ts} | 2 + src/language/{lexer.js => lexer.ts} | 220 +-- src/language/{location.js => location.ts} | 10 +- src/language/{parser.js => parser.ts} | 35 +- src/language/{predicates.js => predicates.ts} | 20 +- .../{printLocation.js => printLocation.ts} | 8 +- src/language/{printer.js => printer.ts} | 30 +- src/language/{source.js => source.ts} | 11 +- src/language/{tokenKind.js => tokenKind.ts} | 2 + src/language/{visitor.js => visitor.ts} | 53 +- .../{objectEntries.js => objectEntries.ts} | 4 +- .../{objectValues.js => objectValues.ts} | 4 +- ...rator-test.js => mapAsyncIterator-test.ts} | 6 +- ...plePubSub-test.js => simplePubSub-test.ts} | 0 .../{simplePubSub.js => simplePubSub.ts} | 10 +- .../{subscribe-test.js => subscribe-test.ts} | 22 +- src/subscription/{index.js => index.ts} | 2 +- ...apAsyncIterator.js => mapAsyncIterator.ts} | 18 +- .../{subscribe.js => subscribe.ts} | 61 +- ...{definition-test.js => definition-test.ts} | 4 +- .../{directive-test.js => directive-test.ts} | 0 .../{enumType-test.js => enumType-test.ts} | 4 +- ...{extensions-test.js => extensions-test.ts} | 2 +- ...spection-test.js => introspection-test.ts} | 0 .../{predicate-test.js => predicate-test.ts} | 11 +- .../{scalars-test.js => scalars-test.ts} | 20 +- .../{schema-test.js => schema-test.ts} | 0 ...{validation-test.js => validation-test.ts} | 8 +- src/type/definition.js | 1579 ----------------- src/type/definition.ts | 1355 ++++++++++++++ src/type/{directives.js => directives.ts} | 57 +- src/type/{index.js => index.ts} | 50 +- .../{introspection.js => introspection.ts} | 29 +- src/type/{scalars.js => scalars.ts} | 26 +- src/type/{schema.js => schema.ts} | 121 +- src/type/validate.js | 668 ------- src/type/validate.ts | 466 +++++ src/utilities/{TypeInfo.js => TypeInfo.ts} | 96 +- .../{TypeInfo-test.js => TypeInfo-test.ts} | 0 ...idName-test.js => assertValidName-test.ts} | 0 ...FromValue-test.js => astFromValue-test.ts} | 0 ...TSchema-test.js => buildASTSchema-test.ts} | 8 +- ...hema-test.js => buildClientSchema-test.ts} | 34 +- ...Value-test.js => coerceInputValue-test.ts} | 4 +- .../{concatAST-test.js => concatAST-test.ts} | 0 ...endSchema-test.js => extendSchema-test.ts} | 12 +- ...es-test.js => findBreakingChanges-test.ts} | 0 ...-test.js => getIntrospectionQuery-test.ts} | 0 ...ionAST-test.js => getOperationAST-test.ts} | 0 ...e-test.js => getOperationRootType-test.ts} | 2 +- ...est.js => introspectionFromSchema-test.ts} | 2 +- ...est.js => lexicographicSortSchema-test.ts} | 0 ...rintSchema-test.js => printSchema-test.ts} | 6 +- ...ons-test.js => separateOperations-test.ts} | 0 ...fuzz.js => stripIgnoredCharacters-fuzz.ts} | 0 ...test.js => stripIgnoredCharacters-test.ts} | 6 +- ...rators-test.js => typeComparators-test.ts} | 4 +- ...ueFromAST-test.js => valueFromAST-test.ts} | 6 +- ...ed-test.js => valueFromASTUntyped-test.ts} | 7 +- ...{assertValidName.js => assertValidName.ts} | 0 .../{astFromValue.js => astFromValue.ts} | 11 +- .../{buildASTSchema.js => buildASTSchema.ts} | 24 +- ...ldClientSchema.js => buildClientSchema.ts} | 12 +- ...oerceInputValue.js => coerceInputValue.ts} | 24 +- src/utilities/{concatAST.js => concatAST.ts} | 4 +- .../{extendSchema.js => extendSchema.ts} | 94 +- ...akingChanges.js => findBreakingChanges.ts} | 58 +- src/utilities/getIntrospectionQuery.js | 298 ---- src/utilities/getIntrospectionQuery.ts | 305 ++++ ...{getOperationAST.js => getOperationAST.ts} | 6 +- ...ionRootType.js => getOperationRootType.ts} | 6 +- src/utilities/{index.js => index.ts} | 6 +- ...omSchema.js => introspectionFromSchema.ts} | 6 +- ...rtSchema.js => lexicographicSortSchema.ts} | 37 +- .../{printSchema.js => printSchema.ts} | 18 +- ...ateOperations.js => separateOperations.ts} | 4 +- ...haracters.js => stripIgnoredCharacters.ts} | 0 ...{typeComparators.js => typeComparators.ts} | 4 +- .../{typeFromAST.js => typeFromAST.ts} | 13 +- .../{valueFromAST.js => valueFromAST.ts} | 16 +- ...omASTUntyped.js => valueFromASTUntyped.ts} | 10 +- ...idationContext.js => ValidationContext.ts} | 72 +- ...t.js => ExecutableDefinitionsRule-test.ts} | 0 ...est.js => FieldsOnCorrectTypeRule-test.ts} | 2 +- ... => FragmentsOnCompositeTypesRule-test.ts} | 0 ...test.js => KnownArgumentNamesRule-test.ts} | 2 +- ...le-test.js => KnownDirectivesRule-test.ts} | 2 +- ...test.js => KnownFragmentNamesRule-test.ts} | 0 ...ule-test.js => KnownTypeNamesRule-test.ts} | 2 +- ....js => LoneAnonymousOperationRule-test.ts} | 0 ...st.js => LoneSchemaDefinitionRule-test.ts} | 2 +- ...test.js => NoDeprecatedCustomRule-test.ts} | 0 ...e-test.js => NoFragmentCyclesRule-test.ts} | 0 ...> NoSchemaIntrospectionCustomRule-test.ts} | 0 ...st.js => NoUndefinedVariablesRule-test.ts} | 0 ...-test.js => NoUnusedFragmentsRule-test.ts} | 0 ...-test.js => NoUnusedVariablesRule-test.ts} | 0 ... OverlappingFieldsCanBeMergedRule-test.ts} | 2 +- ...js => PossibleFragmentSpreadsRule-test.ts} | 0 ....js => PossibleTypeExtensionsRule-test.ts} | 2 +- ... => ProvidedRequiredArgumentsRule-test.ts} | 2 +- ...fsRule-test.js => ScalarLeafsRule-test.ts} | 0 ...s => SingleFieldSubscriptionsRule-test.ts} | 0 ...est.js => UniqueArgumentNamesRule-test.ts} | 0 ...st.js => UniqueDirectiveNamesRule-test.ts} | 2 +- ...> UniqueDirectivesPerLocationRule-test.ts} | 2 +- ...st.js => UniqueEnumValueNamesRule-test.ts} | 2 +- ...=> UniqueFieldDefinitionNamesRule-test.ts} | 2 +- ...est.js => UniqueFragmentNamesRule-test.ts} | 0 ...t.js => UniqueInputFieldNamesRule-test.ts} | 0 ...st.js => UniqueOperationNamesRule-test.ts} | 0 ...st.js => UniqueOperationTypesRule-test.ts} | 2 +- ...le-test.js => UniqueTypeNamesRule-test.ts} | 2 +- ...est.js => UniqueVariableNamesRule-test.ts} | 0 ...est.js => ValuesOfCorrectTypeRule-test.ts} | 0 ....js => VariablesAreInputTypesRule-test.ts} | 0 ...=> VariablesInAllowedPositionRule-test.ts} | 0 .../__tests__/{harness.js => harness.ts} | 4 +- ...{validation-test.js => validation-test.ts} | 4 +- src/validation/{index.js => index.ts} | 2 +- ...nsRule.js => ExecutableDefinitionsRule.ts} | 4 +- ...TypeRule.js => FieldsOnCorrectTypeRule.ts} | 12 +- ...le.js => FragmentsOnCompositeTypesRule.ts} | 4 +- ...NamesRule.js => KnownArgumentNamesRule.ts} | 7 +- ...rectivesRule.js => KnownDirectivesRule.ts} | 15 +- ...NamesRule.js => KnownFragmentNamesRule.ts} | 4 +- ...TypeNamesRule.js => KnownTypeNamesRule.ts} | 11 +- ...nRule.js => LoneAnonymousOperationRule.ts} | 4 +- ...ionRule.js => LoneSchemaDefinitionRule.ts} | 4 +- ...tCyclesRule.js => NoFragmentCyclesRule.ts} | 6 +- ...lesRule.js => NoUndefinedVariablesRule.ts} | 4 +- ...gmentsRule.js => NoUnusedFragmentsRule.ts} | 4 +- ...iablesRule.js => NoUnusedVariablesRule.ts} | 4 +- ...js => OverlappingFieldsCanBeMergedRule.ts} | 33 +- ...Rule.js => PossibleFragmentSpreadsRule.ts} | 8 +- ...sRule.js => PossibleTypeExtensionsRule.ts} | 12 +- ...le.js => ProvidedRequiredArgumentsRule.ts} | 9 +- ...{ScalarLeafsRule.js => ScalarLeafsRule.ts} | 6 +- ...ule.js => SingleFieldSubscriptionsRule.ts} | 6 +- ...amesRule.js => UniqueArgumentNamesRule.ts} | 4 +- ...mesRule.js => UniqueDirectiveNamesRule.ts} | 4 +- ....js => UniqueDirectivesPerLocationRule.ts} | 7 +- ...mesRule.js => UniqueEnumValueNamesRule.ts} | 6 +- ...e.js => UniqueFieldDefinitionNamesRule.ts} | 15 +- ...amesRule.js => UniqueFragmentNamesRule.ts} | 4 +- ...esRule.js => UniqueInputFieldNamesRule.ts} | 4 +- ...mesRule.js => UniqueOperationNamesRule.ts} | 4 +- ...pesRule.js => UniqueOperationTypesRule.ts} | 9 +- ...ypeNamesRule.js => UniqueTypeNamesRule.ts} | 6 +- ...amesRule.js => UniqueVariableNamesRule.ts} | 6 +- ...TypeRule.js => ValuesOfCorrectTypeRule.ts} | 14 +- ...sRule.js => VariablesAreInputTypesRule.ts} | 10 +- ...e.js => VariablesInAllowedPositionRule.ts} | 14 +- ...ustomRule.js => NoDeprecatedCustomRule.ts} | 4 +- ....js => NoSchemaIntrospectionCustomRule.ts} | 6 +- .../{specifiedRules.js => specifiedRules.ts} | 0 src/validation/{validate.js => validate.ts} | 20 +- src/{version.js => version.ts} | 0 252 files changed, 4162 insertions(+), 4583 deletions(-) rename src/__testUtils__/__tests__/{dedent-test.js => dedent-test.ts} (100%) rename src/__testUtils__/__tests__/{genFuzzStrings-test.js => genFuzzStrings-test.ts} (94%) rename src/__testUtils__/__tests__/{inspectStr-test.js => inspectStr-test.ts} (100%) rename src/__testUtils__/__tests__/{resolveOnNextTick-test.js => resolveOnNextTick-test.ts} (100%) rename src/__testUtils__/{dedent.js => dedent.ts} (93%) rename src/__testUtils__/{genFuzzStrings.js => genFuzzStrings.ts} (83%) rename src/__testUtils__/{inspectStr.js => inspectStr.ts} (76%) rename src/__testUtils__/{kitchenSinkQuery.js => kitchenSinkQuery.ts} (97%) rename src/__testUtils__/{kitchenSinkSDL.js => kitchenSinkSDL.ts} (100%) rename src/__testUtils__/{resolveOnNextTick.js => resolveOnNextTick.ts} (100%) rename src/__tests__/{starWarsData.js => starWarsData.ts} (84%) rename src/__tests__/{starWarsIntrospection-test.js => starWarsIntrospection-test.ts} (100%) rename src/__tests__/{starWarsQuery-test.js => starWarsQuery-test.ts} (100%) rename src/__tests__/{starWarsSchema.js => starWarsSchema.ts} (100%) rename src/__tests__/{starWarsValidation-test.js => starWarsValidation-test.ts} (100%) rename src/__tests__/{version-test.js => version-test.ts} (89%) rename src/error/{GraphQLError.js => GraphQLError.ts} (79%) rename src/error/__tests__/{GraphQLError-test.js => GraphQLError-test.ts} (100%) rename src/error/__tests__/{formatError-test.js => formatError-test.ts} (100%) rename src/error/__tests__/{locatedError-test.js => locatedError-test.ts} (77%) rename src/error/{formatError.js => formatError.ts} (81%) rename src/error/{index.js => index.ts} (76%) rename src/error/{locatedError.js => locatedError.ts} (72%) rename src/error/{syntaxError.js => syntaxError.ts} (89%) rename src/execution/__tests__/{abstract-test.js => abstract-test.ts} (97%) rename src/execution/__tests__/{directives-test.js => directives-test.ts} (100%) rename src/execution/__tests__/{executor-test.js => executor-test.ts} (99%) rename src/execution/__tests__/{lists-test.js => lists-test.ts} (96%) rename src/execution/__tests__/{mutations-test.js => mutations-test.ts} (100%) rename src/execution/__tests__/{nonnull-test.js => nonnull-test.ts} (99%) rename src/execution/__tests__/{resolve-test.js => resolve-test.ts} (93%) rename src/execution/__tests__/{schema-test.js => schema-test.ts} (100%) rename src/execution/__tests__/{sync-test.js => sync-test.ts} (100%) rename src/execution/__tests__/{union-interface-test.js => union-interface-test.ts} (100%) rename src/execution/__tests__/{variables-test.js => variables-test.ts} (99%) rename src/execution/{execute.js => execute.ts} (90%) rename src/execution/{index.js => index.ts} (95%) rename src/execution/{values.js => values.ts} (87%) rename src/{graphql.js => graphql.ts} (84%) rename src/{index.js => index.ts} (71%) delete mode 100644 src/jsutils/ObjMap.js create mode 100644 src/jsutils/ObjMap.ts rename src/jsutils/{Path.js => Path.ts} (62%) delete mode 100644 src/jsutils/PromiseOrValue.js create mode 100644 src/jsutils/PromiseOrValue.ts rename src/jsutils/__tests__/{didYouMean-test.js => didYouMean-test.ts} (100%) rename src/jsutils/__tests__/{identityFunc-test.js => identityFunc-test.ts} (100%) rename src/jsutils/__tests__/{inspect-test.js => inspect-test.ts} (98%) rename src/jsutils/__tests__/{instanceOf-test.js => instanceOf-test.ts} (100%) rename src/jsutils/__tests__/{invariant-test.js => invariant-test.ts} (100%) rename src/jsutils/__tests__/{isAsyncIterable-test.js => isAsyncIterable-test.ts} (100%) rename src/jsutils/__tests__/{isCollection-test.js => isCollection-test.ts} (100%) rename src/jsutils/__tests__/{isObjectLike-test.js => isObjectLike-test.ts} (100%) rename src/jsutils/__tests__/{suggestionList-test.js => suggestionList-test.ts} (100%) rename src/jsutils/__tests__/{toObjMap-test.js => toObjMap-test.ts} (96%) rename src/jsutils/{devAssert.js => devAssert.ts} (71%) rename src/jsutils/{didYouMean.js => didYouMean.ts} (89%) rename src/jsutils/{identityFunc.js => identityFunc.ts} (100%) rename src/jsutils/{inspect.js => inspect.ts} (87%) rename src/jsutils/{instanceOf.js => instanceOf.ts} (64%) rename src/jsutils/{invariant.js => invariant.ts} (76%) rename src/jsutils/{isAsyncIterable.js => isAsyncIterable.ts} (81%) rename src/jsutils/{isCollection.js => isCollection.ts} (92%) rename src/jsutils/{isObjectLike.js => isObjectLike.ts} (72%) rename src/jsutils/{isPromise.js => isPromise.ts} (73%) rename src/jsutils/{keyMap.js => keyMap.ts} (92%) rename src/jsutils/{keyValMap.js => keyValMap.ts} (91%) rename src/jsutils/{mapValue.js => mapValue.ts} (91%) rename src/jsutils/{memoize3.js => memoize3.ts} (75%) rename src/jsutils/{printPathArray.js => printPathArray.ts} (84%) rename src/jsutils/{promiseForObject.js => promiseForObject.ts} (94%) rename src/jsutils/{promiseReduce.js => promiseReduce.ts} (82%) rename src/jsutils/{suggestionList.js => suggestionList.ts} (99%) rename src/jsutils/{toObjMap.js => toObjMap.ts} (97%) rename src/language/__tests__/{blockString-fuzz.js => blockString-fuzz.ts} (100%) rename src/language/__tests__/{blockString-test.js => blockString-test.ts} (100%) rename src/language/__tests__/{lexer-test.js => lexer-test.ts} (100%) rename src/language/__tests__/{parser-test.js => parser-test.ts} (100%) rename src/language/__tests__/{predicates-test.js => predicates-test.ts} (95%) rename src/language/__tests__/{printLocation-test.js => printLocation-test.ts} (100%) rename src/language/__tests__/{printer-test.js => printer-test.ts} (97%) rename src/language/__tests__/{schema-parser-test.js => schema-parser-test.ts} (98%) rename src/language/__tests__/{schema-printer-test.js => schema-printer-test.ts} (100%) rename src/language/__tests__/{source-test.js => source-test.ts} (94%) rename src/language/__tests__/{toJSONDeep.js => toJSONDeep.ts} (90%) rename src/language/__tests__/{visitor-test.js => visitor-test.ts} (97%) delete mode 100644 src/language/ast.js create mode 100644 src/language/ast.ts rename src/language/{blockString.js => blockString.ts} (94%) rename src/language/{directiveLocation.js => directiveLocation.ts} (95%) rename src/language/experimentalOnlineParser/{grammar.js => grammar.ts} (98%) rename src/language/experimentalOnlineParser/{index.js => index.ts} (100%) rename src/language/experimentalOnlineParser/{onlineParser.js => onlineParser.ts} (94%) rename src/language/{index.js => index.ts} (83%) rename src/language/{kinds.js => kinds.ts} (97%) rename src/language/{lexer.js => lexer.ts} (86%) rename src/language/{location.js => location.ts} (81%) rename src/language/{parser.js => parser.ts} (98%) rename src/language/{predicates.js => predicates.ts} (79%) rename src/language/{printLocation.js => printLocation.ts} (92%) rename src/language/{printer.js => printer.ts} (93%) rename src/language/{source.js => source.ts} (91%) rename src/language/{tokenKind.js => tokenKind.ts} (93%) rename src/language/{visitor.js => visitor.ts} (89%) rename src/polyfills/{objectEntries.js => objectEntries.ts} (62%) rename src/polyfills/{objectValues.js => objectValues.ts} (60%) rename src/subscription/__tests__/{mapAsyncIterator-test.js => mapAsyncIterator-test.ts} (98%) rename src/subscription/__tests__/{simplePubSub-test.js => simplePubSub-test.ts} (100%) rename src/subscription/__tests__/{simplePubSub.js => simplePubSub.ts} (90%) rename src/subscription/__tests__/{subscribe-test.js => subscribe-test.ts} (98%) rename src/subscription/{index.js => index.ts} (55%) rename src/subscription/{mapAsyncIterator.js => mapAsyncIterator.ts} (83%) rename src/subscription/{subscribe.js => subscribe.ts} (86%) rename src/type/__tests__/{definition-test.js => definition-test.ts} (99%) rename src/type/__tests__/{directive-test.js => directive-test.ts} (100%) rename src/type/__tests__/{enumType-test.js => enumType-test.ts} (99%) rename src/type/__tests__/{extensions-test.js => extensions-test.ts} (99%) rename src/type/__tests__/{introspection-test.js => introspection-test.ts} (100%) rename src/type/__tests__/{predicate-test.js => predicate-test.ts} (98%) rename src/type/__tests__/{scalars-test.js => scalars-test.ts} (98%) rename src/type/__tests__/{schema-test.js => schema-test.ts} (100%) rename src/type/__tests__/{validation-test.js => validation-test.ts} (99%) delete mode 100644 src/type/definition.js create mode 100644 src/type/definition.ts rename src/type/{directives.js => directives.ts} (81%) rename src/type/{index.js => index.ts} (75%) rename src/type/{introspection.js => introspection.ts} (95%) rename src/type/{scalars.js => scalars.ts} (92%) rename src/type/{schema.js => schema.ts} (81%) delete mode 100644 src/type/validate.js create mode 100644 src/type/validate.ts rename src/utilities/{TypeInfo.js => TypeInfo.ts} (79%) rename src/utilities/__tests__/{TypeInfo-test.js => TypeInfo-test.ts} (100%) rename src/utilities/__tests__/{assertValidName-test.js => assertValidName-test.ts} (100%) rename src/utilities/__tests__/{astFromValue-test.js => astFromValue-test.ts} (100%) rename src/utilities/__tests__/{buildASTSchema-test.js => buildASTSchema-test.ts} (99%) rename src/utilities/__tests__/{buildClientSchema-test.js => buildClientSchema-test.ts} (96%) rename src/utilities/__tests__/{coerceInputValue-test.js => coerceInputValue-test.ts} (98%) rename src/utilities/__tests__/{concatAST-test.js => concatAST-test.ts} (100%) rename src/utilities/__tests__/{extendSchema-test.js => extendSchema-test.ts} (99%) rename src/utilities/__tests__/{findBreakingChanges-test.js => findBreakingChanges-test.ts} (100%) rename src/utilities/__tests__/{getIntrospectionQuery-test.js => getIntrospectionQuery-test.ts} (100%) rename src/utilities/__tests__/{getOperationAST-test.js => getOperationAST-test.ts} (100%) rename src/utilities/__tests__/{getOperationRootType-test.js => getOperationRootType-test.ts} (98%) rename src/utilities/__tests__/{introspectionFromSchema-test.js => introspectionFromSchema-test.ts} (95%) rename src/utilities/__tests__/{lexicographicSortSchema-test.js => lexicographicSortSchema-test.ts} (100%) rename src/utilities/__tests__/{printSchema-test.js => printSchema-test.ts} (99%) rename src/utilities/__tests__/{separateOperations-test.js => separateOperations-test.ts} (100%) rename src/utilities/__tests__/{stripIgnoredCharacters-fuzz.js => stripIgnoredCharacters-fuzz.ts} (100%) rename src/utilities/__tests__/{stripIgnoredCharacters-test.js => stripIgnoredCharacters-test.ts} (99%) rename src/utilities/__tests__/{typeComparators-test.js => typeComparators-test.ts} (97%) rename src/utilities/__tests__/{valueFromAST-test.js => valueFromAST-test.ts} (98%) rename src/utilities/__tests__/{valueFromASTUntyped-test.js => valueFromASTUntyped-test.ts} (93%) rename src/utilities/{assertValidName.js => assertValidName.ts} (100%) rename src/utilities/{astFromValue.js => astFromValue.ts} (94%) rename src/utilities/{buildASTSchema.js => buildASTSchema.ts} (83%) rename src/utilities/{buildClientSchema.js => buildClientSchema.ts} (98%) rename src/utilities/{coerceInputValue.js => coerceInputValue.ts} (92%) rename src/utilities/{concatAST.js => concatAST.ts} (82%) rename src/utilities/{extendSchema.js => extendSchema.ts} (91%) rename src/utilities/{findBreakingChanges.js => findBreakingChanges.ts} (93%) delete mode 100644 src/utilities/getIntrospectionQuery.js create mode 100644 src/utilities/getIntrospectionQuery.ts rename src/utilities/{getOperationAST.js => getOperationAST.ts} (83%) rename src/utilities/{getOperationRootType.js => getOperationRootType.ts} (90%) rename src/utilities/{index.js => index.ts} (95%) rename src/utilities/{introspectionFromSchema.js => introspectionFromSchema.ts} (91%) rename src/utilities/{lexicographicSortSchema.js => lexicographicSortSchema.ts} (84%) rename src/utilities/{printSchema.js => printSchema.ts} (94%) rename src/utilities/{separateOperations.js => separateOperations.ts} (95%) rename src/utilities/{stripIgnoredCharacters.js => stripIgnoredCharacters.ts} (100%) rename src/utilities/{typeComparators.js => typeComparators.ts} (96%) rename src/utilities/{typeFromAST.js => typeFromAST.ts} (85%) rename src/utilities/{valueFromAST.js => valueFromAST.ts} (93%) rename src/utilities/{valueFromASTUntyped.js => valueFromASTUntyped.ts} (87%) rename src/validation/{ValidationContext.js => ValidationContext.ts} (75%) rename src/validation/__tests__/{ExecutableDefinitionsRule-test.js => ExecutableDefinitionsRule-test.ts} (100%) rename src/validation/__tests__/{FieldsOnCorrectTypeRule-test.js => FieldsOnCorrectTypeRule-test.ts} (99%) rename src/validation/__tests__/{FragmentsOnCompositeTypesRule-test.js => FragmentsOnCompositeTypesRule-test.ts} (100%) rename src/validation/__tests__/{KnownArgumentNamesRule-test.js => KnownArgumentNamesRule-test.ts} (99%) rename src/validation/__tests__/{KnownDirectivesRule-test.js => KnownDirectivesRule-test.ts} (99%) rename src/validation/__tests__/{KnownFragmentNamesRule-test.js => KnownFragmentNamesRule-test.ts} (100%) rename src/validation/__tests__/{KnownTypeNamesRule-test.js => KnownTypeNamesRule-test.ts} (99%) rename src/validation/__tests__/{LoneAnonymousOperationRule-test.js => LoneAnonymousOperationRule-test.ts} (100%) rename src/validation/__tests__/{LoneSchemaDefinitionRule-test.js => LoneSchemaDefinitionRule-test.ts} (98%) rename src/validation/__tests__/{NoDeprecatedCustomRule-test.js => NoDeprecatedCustomRule-test.ts} (100%) rename src/validation/__tests__/{NoFragmentCyclesRule-test.js => NoFragmentCyclesRule-test.ts} (100%) rename src/validation/__tests__/{NoSchemaIntrospectionCustomRule-test.js => NoSchemaIntrospectionCustomRule-test.ts} (100%) rename src/validation/__tests__/{NoUndefinedVariablesRule-test.js => NoUndefinedVariablesRule-test.ts} (100%) rename src/validation/__tests__/{NoUnusedFragmentsRule-test.js => NoUnusedFragmentsRule-test.ts} (100%) rename src/validation/__tests__/{NoUnusedVariablesRule-test.js => NoUnusedVariablesRule-test.ts} (100%) rename src/validation/__tests__/{OverlappingFieldsCanBeMergedRule-test.js => OverlappingFieldsCanBeMergedRule-test.ts} (99%) rename src/validation/__tests__/{PossibleFragmentSpreadsRule-test.js => PossibleFragmentSpreadsRule-test.ts} (100%) rename src/validation/__tests__/{PossibleTypeExtensionsRule-test.js => PossibleTypeExtensionsRule-test.ts} (99%) rename src/validation/__tests__/{ProvidedRequiredArgumentsRule-test.js => ProvidedRequiredArgumentsRule-test.ts} (99%) rename src/validation/__tests__/{ScalarLeafsRule-test.js => ScalarLeafsRule-test.ts} (100%) rename src/validation/__tests__/{SingleFieldSubscriptionsRule-test.js => SingleFieldSubscriptionsRule-test.ts} (100%) rename src/validation/__tests__/{UniqueArgumentNamesRule-test.js => UniqueArgumentNamesRule-test.ts} (100%) rename src/validation/__tests__/{UniqueDirectiveNamesRule-test.js => UniqueDirectiveNamesRule-test.ts} (97%) rename src/validation/__tests__/{UniqueDirectivesPerLocationRule-test.js => UniqueDirectivesPerLocationRule-test.ts} (99%) rename src/validation/__tests__/{UniqueEnumValueNamesRule-test.js => UniqueEnumValueNamesRule-test.ts} (98%) rename src/validation/__tests__/{UniqueFieldDefinitionNamesRule-test.js => UniqueFieldDefinitionNamesRule-test.ts} (99%) rename src/validation/__tests__/{UniqueFragmentNamesRule-test.js => UniqueFragmentNamesRule-test.ts} (100%) rename src/validation/__tests__/{UniqueInputFieldNamesRule-test.js => UniqueInputFieldNamesRule-test.ts} (100%) rename src/validation/__tests__/{UniqueOperationNamesRule-test.js => UniqueOperationNamesRule-test.ts} (100%) rename src/validation/__tests__/{UniqueOperationTypesRule-test.js => UniqueOperationTypesRule-test.ts} (99%) rename src/validation/__tests__/{UniqueTypeNamesRule-test.js => UniqueTypeNamesRule-test.ts} (98%) rename src/validation/__tests__/{UniqueVariableNamesRule-test.js => UniqueVariableNamesRule-test.ts} (100%) rename src/validation/__tests__/{ValuesOfCorrectTypeRule-test.js => ValuesOfCorrectTypeRule-test.ts} (100%) rename src/validation/__tests__/{VariablesAreInputTypesRule-test.js => VariablesAreInputTypesRule-test.ts} (100%) rename src/validation/__tests__/{VariablesInAllowedPositionRule-test.js => VariablesInAllowedPositionRule-test.ts} (100%) rename src/validation/__tests__/{harness.js => harness.ts} (97%) rename src/validation/__tests__/{validation-test.js => validation-test.ts} (97%) rename src/validation/{index.js => index.ts} (98%) rename src/validation/rules/{ExecutableDefinitionsRule.js => ExecutableDefinitionsRule.ts} (89%) rename src/validation/rules/{FieldsOnCorrectTypeRule.js => FieldsOnCorrectTypeRule.ts} (93%) rename src/validation/rules/{FragmentsOnCompositeTypesRule.js => FragmentsOnCompositeTypesRule.ts} (92%) rename src/validation/rules/{KnownArgumentNamesRule.js => KnownArgumentNamesRule.ts} (94%) rename src/validation/rules/{KnownDirectivesRule.js => KnownDirectivesRule.ts} (90%) rename src/validation/rules/{KnownFragmentNamesRule.js => KnownFragmentNamesRule.ts} (83%) rename src/validation/rules/{KnownTypeNamesRule.js => KnownTypeNamesRule.ts} (88%) rename src/validation/rules/{LoneAnonymousOperationRule.js => LoneAnonymousOperationRule.ts} (87%) rename src/validation/rules/{LoneSchemaDefinitionRule.js => LoneSchemaDefinitionRule.ts} (88%) rename src/validation/rules/{NoFragmentCyclesRule.js => NoFragmentCyclesRule.ts} (91%) rename src/validation/rules/{NoUndefinedVariablesRule.js => NoUndefinedVariablesRule.ts} (90%) rename src/validation/rules/{NoUnusedFragmentsRule.js => NoUnusedFragmentsRule.ts} (91%) rename src/validation/rules/{NoUnusedVariablesRule.js => NoUnusedVariablesRule.ts} (91%) rename src/validation/rules/{OverlappingFieldsCanBeMergedRule.js => OverlappingFieldsCanBeMergedRule.ts} (97%) rename src/validation/rules/{PossibleFragmentSpreadsRule.js => PossibleFragmentSpreadsRule.ts} (90%) rename src/validation/rules/{PossibleTypeExtensionsRule.js => PossibleTypeExtensionsRule.ts} (91%) rename src/validation/rules/{ProvidedRequiredArgumentsRule.js => ProvidedRequiredArgumentsRule.ts} (94%) rename src/validation/rules/{ScalarLeafsRule.js => ScalarLeafsRule.ts} (88%) rename src/validation/rules/{SingleFieldSubscriptionsRule.js => SingleFieldSubscriptionsRule.ts} (81%) rename src/validation/rules/{UniqueArgumentNamesRule.js => UniqueArgumentNamesRule.ts} (87%) rename src/validation/rules/{UniqueDirectiveNamesRule.js => UniqueDirectiveNamesRule.ts} (89%) rename src/validation/rules/{UniqueDirectivesPerLocationRule.js => UniqueDirectivesPerLocationRule.ts} (94%) rename src/validation/rules/{UniqueEnumValueNamesRule.js => UniqueEnumValueNamesRule.ts} (93%) rename src/validation/rules/{UniqueFieldDefinitionNamesRule.js => UniqueFieldDefinitionNamesRule.ts} (88%) rename src/validation/rules/{UniqueFragmentNamesRule.js => UniqueFragmentNamesRule.ts} (86%) rename src/validation/rules/{UniqueInputFieldNamesRule.js => UniqueInputFieldNamesRule.ts} (88%) rename src/validation/rules/{UniqueOperationNamesRule.js => UniqueOperationNamesRule.ts} (87%) rename src/validation/rules/{UniqueOperationTypesRule.js => UniqueOperationTypesRule.ts} (88%) rename src/validation/rules/{UniqueTypeNamesRule.js => UniqueTypeNamesRule.ts} (87%) rename src/validation/rules/{UniqueVariableNamesRule.js => UniqueVariableNamesRule.ts} (82%) rename src/validation/rules/{ValuesOfCorrectTypeRule.js => ValuesOfCorrectTypeRule.ts} (93%) rename src/validation/rules/{VariablesAreInputTypesRule.js => VariablesAreInputTypesRule.ts} (76%) rename src/validation/rules/{VariablesInAllowedPositionRule.js => VariablesInAllowedPositionRule.ts} (89%) rename src/validation/rules/custom/{NoDeprecatedCustomRule.js => NoDeprecatedCustomRule.ts} (96%) rename src/validation/rules/custom/{NoSchemaIntrospectionCustomRule.js => NoSchemaIntrospectionCustomRule.ts} (85%) rename src/validation/{specifiedRules.js => specifiedRules.ts} (100%) rename src/validation/{validate.js => validate.ts} (86%) rename src/{version.js => version.ts} (100%) diff --git a/src/__testUtils__/__tests__/dedent-test.js b/src/__testUtils__/__tests__/dedent-test.ts similarity index 100% rename from src/__testUtils__/__tests__/dedent-test.js rename to src/__testUtils__/__tests__/dedent-test.ts diff --git a/src/__testUtils__/__tests__/genFuzzStrings-test.js b/src/__testUtils__/__tests__/genFuzzStrings-test.ts similarity index 94% rename from src/__testUtils__/__tests__/genFuzzStrings-test.js rename to src/__testUtils__/__tests__/genFuzzStrings-test.ts index 75da1b63cc0..92ea5c592d9 100644 --- a/src/__testUtils__/__tests__/genFuzzStrings-test.js +++ b/src/__testUtils__/__tests__/genFuzzStrings-test.ts @@ -3,10 +3,10 @@ import { describe, it } from 'mocha'; import genFuzzStrings from '../genFuzzStrings'; -function expectFuzzStrings(options: {| - allowedChars: Array, - maxLength: number, -|}) { +function expectFuzzStrings(options: { + allowedChars: Array; + maxLength: number; +}) { return expect(Array.from(genFuzzStrings(options))); } diff --git a/src/__testUtils__/__tests__/inspectStr-test.js b/src/__testUtils__/__tests__/inspectStr-test.ts similarity index 100% rename from src/__testUtils__/__tests__/inspectStr-test.js rename to src/__testUtils__/__tests__/inspectStr-test.ts diff --git a/src/__testUtils__/__tests__/resolveOnNextTick-test.js b/src/__testUtils__/__tests__/resolveOnNextTick-test.ts similarity index 100% rename from src/__testUtils__/__tests__/resolveOnNextTick-test.js rename to src/__testUtils__/__tests__/resolveOnNextTick-test.ts diff --git a/src/__testUtils__/dedent.js b/src/__testUtils__/dedent.ts similarity index 93% rename from src/__testUtils__/dedent.js rename to src/__testUtils__/dedent.ts index c4b8e8da7b1..15c89cadbb7 100644 --- a/src/__testUtils__/dedent.js +++ b/src/__testUtils__/dedent.ts @@ -11,8 +11,8 @@ * str === "{\n test\n}\n"; */ export default function dedent( - strings: $ReadOnlyArray, - ...values: $ReadOnlyArray + strings: ReadonlyArray, + ...values: ReadonlyArray ): string { let str = ''; diff --git a/src/__testUtils__/genFuzzStrings.js b/src/__testUtils__/genFuzzStrings.ts similarity index 83% rename from src/__testUtils__/genFuzzStrings.js rename to src/__testUtils__/genFuzzStrings.ts index 4ead99080ca..b9e4a0af7e1 100644 --- a/src/__testUtils__/genFuzzStrings.js +++ b/src/__testUtils__/genFuzzStrings.ts @@ -1,10 +1,10 @@ /** * Generator that produces all possible combinations of allowed characters. */ -export default function* genFuzzStrings(options: {| - allowedChars: Array, - maxLength: number, -|}): Generator { +export default function* genFuzzStrings(options: { + allowedChars: Array; + maxLength: number; +}): Generator { const { allowedChars, maxLength } = options; const numAllowedChars = allowedChars.length; diff --git a/src/__testUtils__/inspectStr.js b/src/__testUtils__/inspectStr.ts similarity index 76% rename from src/__testUtils__/inspectStr.js rename to src/__testUtils__/inspectStr.ts index a99a28150ad..2fce34558e0 100644 --- a/src/__testUtils__/inspectStr.js +++ b/src/__testUtils__/inspectStr.ts @@ -1,7 +1,7 @@ /** * Special inspect function to produce readable string literal for error messages in tests */ -export default function inspectStr(str: ?string): string { +export default function inspectStr(str: string | null | undefined): string { if (str == null) { return 'null'; } diff --git a/src/__testUtils__/kitchenSinkQuery.js b/src/__testUtils__/kitchenSinkQuery.ts similarity index 97% rename from src/__testUtils__/kitchenSinkQuery.js rename to src/__testUtils__/kitchenSinkQuery.ts index 2ccdc9dc92e..a7c9cf9d029 100644 --- a/src/__testUtils__/kitchenSinkQuery.js +++ b/src/__testUtils__/kitchenSinkQuery.ts @@ -1,4 +1,3 @@ -// $FlowFixMe[incompatible-call] const kitchenSinkQuery: string = String.raw` query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery { whoever123is: node(id: [123, 456]) { diff --git a/src/__testUtils__/kitchenSinkSDL.js b/src/__testUtils__/kitchenSinkSDL.ts similarity index 100% rename from src/__testUtils__/kitchenSinkSDL.js rename to src/__testUtils__/kitchenSinkSDL.ts diff --git a/src/__testUtils__/resolveOnNextTick.js b/src/__testUtils__/resolveOnNextTick.ts similarity index 100% rename from src/__testUtils__/resolveOnNextTick.js rename to src/__testUtils__/resolveOnNextTick.ts diff --git a/src/__tests__/starWarsData.js b/src/__tests__/starWarsData.ts similarity index 84% rename from src/__tests__/starWarsData.js rename to src/__tests__/starWarsData.ts index 7e1917b8bd9..a1263bff2b1 100644 --- a/src/__tests__/starWarsData.js +++ b/src/__tests__/starWarsData.ts @@ -3,30 +3,29 @@ * They represent the shape of the data visited during field resolution. */ export type Character = { - id: string, - name: string, - friends: Array, - appearsIn: Array, - ... + id: string; + name: string; + friends: Array; + appearsIn: Array; }; -export type Human = {| - type: 'Human', - id: string, - name: string, - friends: Array, - appearsIn: Array, - homePlanet?: string, -|}; - -export type Droid = {| - type: 'Droid', - id: string, - name: string, - friends: Array, - appearsIn: Array, - primaryFunction: string, -|}; +export type Human = { + type: 'Human'; + id: string; + name: string; + friends: Array; + appearsIn: Array; + homePlanet?: string; +}; + +export type Droid = { + type: 'Droid'; + id: string; + name: string; + friends: Array; + appearsIn: Array; + primaryFunction: string; +}; /** * This defines a basic set of data for our Star Wars Schema. @@ -35,7 +34,6 @@ export type Droid = {| * fetching this data from a backend service rather than from hardcoded * JSON objects in a more complex demo. */ - const luke: Human = { type: 'Human', id: '1000', @@ -79,7 +77,9 @@ const tarkin: Human = { appearsIn: [4], }; -const humanData: {| [id: string]: Human |} = { +const humanData: { + [id: string]: Human; +} = { [luke.id]: luke, [vader.id]: vader, [han.id]: han, @@ -105,7 +105,9 @@ const artoo: Droid = { primaryFunction: 'Astromech', }; -const droidData: {| [id: string]: Droid |} = { +const droidData: { + [id: string]: Droid; +} = { [threepio.id]: threepio, [artoo.id]: artoo, }; diff --git a/src/__tests__/starWarsIntrospection-test.js b/src/__tests__/starWarsIntrospection-test.ts similarity index 100% rename from src/__tests__/starWarsIntrospection-test.js rename to src/__tests__/starWarsIntrospection-test.ts diff --git a/src/__tests__/starWarsQuery-test.js b/src/__tests__/starWarsQuery-test.ts similarity index 100% rename from src/__tests__/starWarsQuery-test.js rename to src/__tests__/starWarsQuery-test.ts diff --git a/src/__tests__/starWarsSchema.js b/src/__tests__/starWarsSchema.ts similarity index 100% rename from src/__tests__/starWarsSchema.js rename to src/__tests__/starWarsSchema.ts diff --git a/src/__tests__/starWarsValidation-test.js b/src/__tests__/starWarsValidation-test.ts similarity index 100% rename from src/__tests__/starWarsValidation-test.js rename to src/__tests__/starWarsValidation-test.ts diff --git a/src/__tests__/version-test.js b/src/__tests__/version-test.ts similarity index 89% rename from src/__tests__/version-test.js rename to src/__tests__/version-test.ts index 7d9a0acf0ce..94c9e93ad1f 100644 --- a/src/__tests__/version-test.js +++ b/src/__tests__/version-test.ts @@ -30,8 +30,7 @@ describe('Version', () => { } expect( - `${major}.${minor}.${patch}` + - // istanbul ignore next (Can't be verified on all versions) + `${major}.${minor}.${patch}` + // istanbul ignore next (Can't be verified on all versions) (preReleaseTag !== null ? '-' + preReleaseTag : ''), ).to.equal(version); }); diff --git a/src/error/GraphQLError.js b/src/error/GraphQLError.ts similarity index 79% rename from src/error/GraphQLError.js rename to src/error/GraphQLError.ts index e3c397679f9..ae25d45ea1b 100644 --- a/src/error/GraphQLError.js +++ b/src/error/GraphQLError.ts @@ -1,13 +1,13 @@ // FIXME: // flowlint uninitialized-instance-property:off -import isObjectLike from '../jsutils/isObjectLike'; +import isObjectLike from "../jsutils/isObjectLike"; -import type { ASTNode } from '../language/ast'; -import type { Source } from '../language/source'; -import type { SourceLocation } from '../language/location'; -import { getLocation } from '../language/location'; -import { printLocation, printSourceLocation } from '../language/printLocation'; +import { ASTNode } from "../language/ast"; +import { Source } from "../language/source"; +import { SourceLocation } from "../language/location"; +import { getLocation } from "../language/location"; +import { printLocation, printSourceLocation } from "../language/printLocation"; /** * A GraphQLError describes an Error found during the parse, validate, or @@ -35,7 +35,7 @@ export class GraphQLError extends Error { * * Enumerable, and appears in the result of JSON.stringify(). */ - +locations: $ReadOnlyArray | void; + +locations: ReadonlyArray | void; /** * An array describing the JSON-path into the execution response which @@ -43,12 +43,12 @@ export class GraphQLError extends Error { * * Enumerable, and appears in the result of JSON.stringify(). */ - +path: $ReadOnlyArray | void; + +path: ReadonlyArray | void; /** * An array of GraphQL AST Nodes corresponding to this error. */ - +nodes: $ReadOnlyArray | void; + +nodes: ReadonlyArray | void; /** * The source GraphQL document for the first location of this error. @@ -62,37 +62,27 @@ export class GraphQLError extends Error { * An array of character offsets within the source GraphQL document * which correspond to this error. */ - +positions: $ReadOnlyArray | void; + +positions: ReadonlyArray | void; /** * The original error thrown from a field resolver during execution. */ - +originalError: ?Error; + +originalError: Error | null | undefined; /** * Extension fields to add to the formatted error. */ - +extensions: { [key: string]: mixed, ... } | void; - - constructor( - message: string, - nodes?: $ReadOnlyArray | ASTNode | void | null, - source?: ?Source, - positions?: ?$ReadOnlyArray, - path?: ?$ReadOnlyArray, - originalError?: ?(Error & { +extensions?: mixed, ... }), - extensions?: ?{ [key: string]: mixed, ... }, - ): void { + +extensions: { + [key: string]: unknown; + } | void; + + constructor(message: string, nodes?: ReadonlyArray | ASTNode | void | null, source?: Source | null | undefined, positions?: ReadonlyArray | null | undefined, path?: ReadonlyArray | null | undefined, originalError?: (Error & {readonly extensions?: unknown;}) | null | undefined, extensions?: { + [key: string]: unknown; + } | null | undefined): void { super(message); // Compute list of blame nodes. - const _nodes = Array.isArray(nodes) - ? nodes.length !== 0 - ? nodes - : undefined - : nodes - ? [nodes] - : undefined; + const _nodes = Array.isArray(nodes) ? nodes.length !== 0 ? nodes : undefined : nodes ? [nodes] : undefined; // Compute locations in the source for the given nodes/positions. let _source = source; @@ -115,7 +105,7 @@ export class GraphQLError extends Error { let _locations; if (positions && source) { - _locations = positions.map((pos) => getLocation(source, pos)); + _locations = positions.map(pos => getLocation(source, pos)); } else if (_nodes) { _locations = _nodes.reduce((list, node) => { if (node.loc) { @@ -133,7 +123,7 @@ export class GraphQLError extends Error { } } - Object.defineProperties((this: any), { + Object.defineProperties((this as any), { name: { value: 'GraphQLError' }, message: { value: message, @@ -141,7 +131,7 @@ export class GraphQLError extends Error { // resulting output. This ensures that the simplest possible GraphQL // service adheres to the spec. enumerable: true, - writable: true, + writable: true }, locations: { // Coercing falsy values to undefined ensures they will not be included @@ -150,7 +140,7 @@ export class GraphQLError extends Error { // By being enumerable, JSON.stringify will include `locations` in the // resulting output. This ensures that the simplest possible GraphQL // service adheres to the spec. - enumerable: _locations != null, + enumerable: _locations != null }, path: { // Coercing falsy values to undefined ensures they will not be included @@ -159,19 +149,19 @@ export class GraphQLError extends Error { // By being enumerable, JSON.stringify will include `path` in the // resulting output. This ensures that the simplest possible GraphQL // service adheres to the spec. - enumerable: path != null, + enumerable: path != null }, nodes: { - value: _nodes ?? undefined, + value: _nodes ?? undefined }, source: { - value: _source ?? undefined, + value: _source ?? undefined }, positions: { - value: _positions ?? undefined, + value: _positions ?? undefined }, originalError: { - value: originalError, + value: originalError }, extensions: { // Coercing falsy values to undefined ensures they will not be included @@ -180,8 +170,8 @@ export class GraphQLError extends Error { // By being enumerable, JSON.stringify will include `path` in the // resulting output. This ensures that the simplest possible GraphQL // service adheres to the spec. - enumerable: _extensions != null, - }, + enumerable: _extensions != null + } }); // Include (non-enumerable) stack trace. @@ -189,7 +179,7 @@ export class GraphQLError extends Error { Object.defineProperty(this, 'stack', { value: originalError.stack, writable: true, - configurable: true, + configurable: true }); return; } @@ -201,7 +191,7 @@ export class GraphQLError extends Error { Object.defineProperty(this, 'stack', { value: Error().stack, writable: true, - configurable: true, + configurable: true }); } } @@ -237,4 +227,4 @@ export function printError(error: GraphQLError): string { } return output; -} +} \ No newline at end of file diff --git a/src/error/__tests__/GraphQLError-test.js b/src/error/__tests__/GraphQLError-test.ts similarity index 100% rename from src/error/__tests__/GraphQLError-test.js rename to src/error/__tests__/GraphQLError-test.ts diff --git a/src/error/__tests__/formatError-test.js b/src/error/__tests__/formatError-test.ts similarity index 100% rename from src/error/__tests__/formatError-test.js rename to src/error/__tests__/formatError-test.ts diff --git a/src/error/__tests__/locatedError-test.js b/src/error/__tests__/locatedError-test.ts similarity index 77% rename from src/error/__tests__/locatedError-test.js rename to src/error/__tests__/locatedError-test.ts index 3de473b4c98..a8cf8318d6b 100644 --- a/src/error/__tests__/locatedError-test.js +++ b/src/error/__tests__/locatedError-test.ts @@ -18,19 +18,19 @@ describe('locatedError', () => { it('passes GraphQLError-ish through', () => { const e = new Error('I have a different prototype chain'); - (e: any).locations = []; - (e: any).path = []; - (e: any).nodes = []; - (e: any).source = null; - (e: any).positions = []; - (e: any).name = 'GraphQLError'; + (e as any).locations = []; + (e as any).path = []; + (e as any).nodes = []; + (e as any).source = null; + (e as any).positions = []; + (e as any).name = 'GraphQLError'; expect(locatedError(e, [], [])).to.deep.equal(e); }); it('does not pass through elasticsearch-like errors', () => { const e = new Error('I am from elasticsearch'); - (e: any).path = '/something/feed/_search'; + (e as any).path = '/something/feed/_search'; expect(locatedError(e, [], [])).to.not.deep.equal(e); }); diff --git a/src/error/formatError.js b/src/error/formatError.ts similarity index 81% rename from src/error/formatError.js rename to src/error/formatError.ts index d73cc897b04..fe637a2931d 100644 --- a/src/error/formatError.js +++ b/src/error/formatError.ts @@ -1,8 +1,8 @@ import devAssert from '../jsutils/devAssert'; -import type { SourceLocation } from '../language/location'; +import { SourceLocation } from '../language/location'; -import type { GraphQLError } from './GraphQLError'; +import { GraphQLError } from './GraphQLError'; /** * Given a GraphQLError, format it according to the rules described by the @@ -23,28 +23,33 @@ export function formatError(error: GraphQLError): GraphQLFormattedError { /** * @see https://github.com/graphql/graphql-spec/blob/master/spec/Section%207%20--%20Response.md#errors */ -export type GraphQLFormattedError = {| +export type GraphQLFormattedError = { /** * A short, human-readable summary of the problem that **SHOULD NOT** change * from occurrence to occurrence of the problem, except for purposes of * localization. */ - +message: string, + readonly message: string; + /** * If an error can be associated to a particular point in the requested * GraphQL document, it should contain a list of locations. */ - +locations: $ReadOnlyArray | void, + readonly locations: ReadonlyArray | void; + /** * If an error can be associated to a particular field in the GraphQL result, * it _must_ contain an entry with the key `path` that details the path of * the response field which experienced the error. This allows clients to * identify whether a null result is intentional or caused by a runtime error. */ - +path: $ReadOnlyArray | void, + readonly path: ReadonlyArray | void; + /** * Reserved for implementors to extend the protocol however they see fit, * and hence there are no additional restrictions on its contents. */ - +extensions?: { [key: string]: mixed, ... }, -|}; + readonly extensions?: { + [key: string]: unknown; + }; +}; diff --git a/src/error/index.js b/src/error/index.ts similarity index 76% rename from src/error/index.js rename to src/error/index.ts index 914a6dbe46e..5b69ce096ca 100644 --- a/src/error/index.js +++ b/src/error/index.ts @@ -5,4 +5,4 @@ export { syntaxError } from './syntaxError'; export { locatedError } from './locatedError'; export { formatError } from './formatError'; -export type { GraphQLFormattedError } from './formatError'; +export { GraphQLFormattedError } from './formatError'; diff --git a/src/error/locatedError.js b/src/error/locatedError.ts similarity index 72% rename from src/error/locatedError.js rename to src/error/locatedError.ts index 1b7c3350703..259332073bd 100644 --- a/src/error/locatedError.js +++ b/src/error/locatedError.ts @@ -1,6 +1,6 @@ import inspect from '../jsutils/inspect'; -import type { ASTNode } from '../language/ast'; +import { ASTNode } from '../language/ast'; import { GraphQLError } from './GraphQLError'; @@ -10,9 +10,9 @@ import { GraphQLError } from './GraphQLError'; * document responsible for the original Error. */ export function locatedError( - rawOriginalError: mixed, - nodes: ASTNode | $ReadOnlyArray | void | null, - path?: ?$ReadOnlyArray, + rawOriginalError: unknown, + nodes: ASTNode | ReadonlyArray | void | null, + path?: ReadonlyArray | null | undefined, ): GraphQLError { // Sometimes a non-error is thrown, wrap it as an Error instance to ensure a consistent Error interface. const originalError: Error | GraphQLError = @@ -22,14 +22,14 @@ export function locatedError( // Note: this uses a brand-check to support GraphQL errors originating from other contexts. if (Array.isArray(originalError.path)) { - return (originalError: any); + return originalError as any; } return new GraphQLError( originalError.message, - (originalError: any).nodes ?? nodes, - (originalError: any).source, - (originalError: any).positions, + (originalError as any).nodes ?? nodes, + (originalError as any).source, + (originalError as any).positions, path, originalError, ); diff --git a/src/error/syntaxError.js b/src/error/syntaxError.ts similarity index 89% rename from src/error/syntaxError.js rename to src/error/syntaxError.ts index 21a2dc18e4d..87cba885c3c 100644 --- a/src/error/syntaxError.js +++ b/src/error/syntaxError.ts @@ -1,4 +1,4 @@ -import type { Source } from '../language/source'; +import { Source } from '../language/source'; import { GraphQLError } from './GraphQLError'; diff --git a/src/execution/__tests__/abstract-test.js b/src/execution/__tests__/abstract-test.ts similarity index 97% rename from src/execution/__tests__/abstract-test.js rename to src/execution/__tests__/abstract-test.ts index 519585af0ff..dbb57c3f890 100644 --- a/src/execution/__tests__/abstract-test.js +++ b/src/execution/__tests__/abstract-test.ts @@ -16,11 +16,11 @@ import { buildSchema } from '../../utilities/buildASTSchema'; import { executeSync, execute } from '../execute'; -async function executeQuery(args: {| - schema: GraphQLSchema, - query: string, - rootValue?: mixed, -|}) { +async function executeQuery(args: { + schema: GraphQLSchema; + query: string; + rootValue?: unknown; +}) { const { schema, query, rootValue } = args; const document = parse(query); const result = executeSync({ @@ -533,7 +533,7 @@ describe('Execute: Handles execution of abstract types', () => { } `); - function expectError({ forTypeName }: {| forTypeName: mixed |}) { + function expectError({ forTypeName }: { forTypeName: unknown }) { const rootValue = { pet: { __typename: forTypeName } }; const result = executeSync({ schema, document, rootValue }); return { @@ -569,13 +569,13 @@ describe('Execute: Handles execution of abstract types', () => { ); // FIXME: workaround since we can't inject resolveType into SDL - (schema.getType('Pet'): any).resolveType = () => []; + (schema.getType('Pet') as any).resolveType = () => []; expectError({ forTypeName: undefined }).toEqual( 'Abstract type "Pet" must resolve to an Object type at runtime for field "Query.pet" with value { __typename: undefined }, received "[]".', ); // FIXME: workaround since we can't inject resolveType into SDL - (schema.getType('Pet'): any).resolveType = () => schema.getType('Cat'); + (schema.getType('Pet') as any).resolveType = () => schema.getType('Cat'); expectError({ forTypeName: undefined }).toEqual( 'Support for returning GraphQLObjectType from resolveType was removed in graphql-js@16.0.0 please return type name instead.', ); diff --git a/src/execution/__tests__/directives-test.js b/src/execution/__tests__/directives-test.ts similarity index 100% rename from src/execution/__tests__/directives-test.js rename to src/execution/__tests__/directives-test.ts diff --git a/src/execution/__tests__/executor-test.js b/src/execution/__tests__/executor-test.ts similarity index 99% rename from src/execution/__tests__/executor-test.js rename to src/execution/__tests__/executor-test.ts index d1ea9bb49fd..d3aba46bc7f 100644 --- a/src/execution/__tests__/executor-test.js +++ b/src/execution/__tests__/executor-test.ts @@ -489,7 +489,7 @@ describe('Execute: Handles basic execution tasks', () => { }, asyncReturnErrorWithExtensions() { const error = new Error('Error getting asyncReturnErrorWithExtensions'); - (error: any).extensions = { foo: 'bar' }; + (error as any).extensions = { foo: 'bar' }; return Promise.resolve(error); }, diff --git a/src/execution/__tests__/lists-test.js b/src/execution/__tests__/lists-test.ts similarity index 96% rename from src/execution/__tests__/lists-test.js rename to src/execution/__tests__/lists-test.ts index 926802a51b1..2b04d604c1d 100644 --- a/src/execution/__tests__/lists-test.js +++ b/src/execution/__tests__/lists-test.ts @@ -8,7 +8,7 @@ import { buildSchema } from '../../utilities/buildASTSchema'; import { execute, executeSync } from '../execute'; describe('Execute: Accepts any iterable as list value', () => { - function complete(rootValue: mixed) { + function complete(rootValue: unknown) { return executeSync({ schema: buildSchema('type Query { listField: [String] }'), document: parse('{ listField }'), @@ -65,7 +65,7 @@ describe('Execute: Accepts any iterable as list value', () => { }); describe('Execute: Handles list nullability', () => { - async function complete(args: {| listField: mixed, as: string |}) { + async function complete(args: { listField: unknown; as: string }) { const { listField, as } = args; const schema = buildSchema(`type Query { listField: ${as} }`); const document = parse('{ listField }'); @@ -85,11 +85,11 @@ describe('Execute: Handles list nullability', () => { } return result; - function executeQuery(listValue: mixed) { + function executeQuery(listValue: unknown) { return execute({ schema, document, rootValue: { listField: listValue } }); } - function promisify(value: mixed): Promise { + function promisify(value: unknown): Promise { return value instanceof Error ? Promise.reject(value) : Promise.resolve(value); diff --git a/src/execution/__tests__/mutations-test.js b/src/execution/__tests__/mutations-test.ts similarity index 100% rename from src/execution/__tests__/mutations-test.js rename to src/execution/__tests__/mutations-test.ts diff --git a/src/execution/__tests__/nonnull-test.js b/src/execution/__tests__/nonnull-test.ts similarity index 99% rename from src/execution/__tests__/nonnull-test.js rename to src/execution/__tests__/nonnull-test.ts index 4eb38f12b6e..3e770e05303 100644 --- a/src/execution/__tests__/nonnull-test.js +++ b/src/execution/__tests__/nonnull-test.ts @@ -9,7 +9,7 @@ import { GraphQLNonNull, GraphQLObjectType } from '../../type/definition'; import { buildSchema } from '../../utilities/buildASTSchema'; -import type { ExecutionResult } from '../execute'; +import { ExecutionResult } from '../execute'; import { execute, executeSync } from '../execute'; const syncError = new Error('sync'); @@ -106,7 +106,7 @@ const schema = buildSchema(` function executeQuery( query: string, - rootValue: mixed, + rootValue: unknown, ): ExecutionResult | Promise { return execute({ schema, document: parse(query), rootValue }); } @@ -122,7 +122,7 @@ function patchData(data: ExecutionResult): ExecutionResult { return JSON.parse(patch(JSON.stringify(data))); } -async function executeSyncAndAsync(query: string, rootValue: mixed) { +async function executeSyncAndAsync(query: string, rootValue: unknown) { const syncResult = executeSync({ schema, document: parse(query), rootValue }); const asyncResult = await execute({ schema, diff --git a/src/execution/__tests__/resolve-test.js b/src/execution/__tests__/resolve-test.ts similarity index 93% rename from src/execution/__tests__/resolve-test.js rename to src/execution/__tests__/resolve-test.ts index afe911e7bcf..63c206c41e6 100644 --- a/src/execution/__tests__/resolve-test.js +++ b/src/execution/__tests__/resolve-test.ts @@ -3,7 +3,7 @@ import { describe, it } from 'mocha'; import { parse } from '../../language/parser'; -import type { GraphQLFieldConfig } from '../../type/definition'; +import { GraphQLFieldConfig } from '../../type/definition'; import { GraphQLSchema } from '../../type/schema'; import { GraphQLInt, GraphQLString } from '../../type/scalars'; import { GraphQLObjectType } from '../../type/definition'; @@ -64,7 +64,7 @@ describe('Execute: resolve function', () => { this._num = num; } - test(args: {| addend1: number |}, context: {| addend2: number |}) { + test(args: { addend1: number }, context: { addend2: number }) { return this._num + args.addend1 + context.addend2; } } @@ -95,7 +95,7 @@ describe('Execute: resolve function', () => { resolve: (source, args) => JSON.stringify([source, args]), }); - function executeQuery(query: string, rootValue?: mixed) { + function executeQuery(query: string, rootValue?: unknown) { const document = parse(query); return executeSync({ schema, document, rootValue }); } diff --git a/src/execution/__tests__/schema-test.js b/src/execution/__tests__/schema-test.ts similarity index 100% rename from src/execution/__tests__/schema-test.js rename to src/execution/__tests__/schema-test.ts diff --git a/src/execution/__tests__/sync-test.js b/src/execution/__tests__/sync-test.ts similarity index 100% rename from src/execution/__tests__/sync-test.js rename to src/execution/__tests__/sync-test.ts diff --git a/src/execution/__tests__/union-interface-test.js b/src/execution/__tests__/union-interface-test.ts similarity index 100% rename from src/execution/__tests__/union-interface-test.js rename to src/execution/__tests__/union-interface-test.ts diff --git a/src/execution/__tests__/variables-test.js b/src/execution/__tests__/variables-test.ts similarity index 99% rename from src/execution/__tests__/variables-test.js rename to src/execution/__tests__/variables-test.ts index 9f637dd7edb..5048a131856 100644 --- a/src/execution/__tests__/variables-test.js +++ b/src/execution/__tests__/variables-test.ts @@ -7,7 +7,7 @@ import invariant from '../../jsutils/invariant'; import { Kind } from '../../language/kinds'; import { parse } from '../../language/parser'; -import type { GraphQLArgumentConfig } from '../../type/definition'; +import { GraphQLArgumentConfig } from '../../type/definition'; import { GraphQLSchema } from '../../type/schema'; import { GraphQLString } from '../../type/scalars'; import { @@ -119,7 +119,9 @@ const schema = new GraphQLSchema({ query: TestType }); function executeQuery( query: string, - variableValues?: { [variable: string]: mixed, ... }, + variableValues?: { + [variable: string]: unknown; + }, ) { const document = parse(query); return executeSync({ schema, document, variableValues }); diff --git a/src/execution/execute.js b/src/execution/execute.ts similarity index 90% rename from src/execution/execute.js rename to src/execution/execute.ts index c9c2c6a8093..3ba15de046a 100644 --- a/src/execution/execute.js +++ b/src/execution/execute.ts @@ -1,6 +1,6 @@ -import type { Path } from '../jsutils/Path'; -import type { ObjMap } from '../jsutils/ObjMap'; -import type { PromiseOrValue } from '../jsutils/PromiseOrValue'; +import { Path } from '../jsutils/Path'; +import { ObjMap } from '../jsutils/ObjMap'; +import { PromiseOrValue } from '../jsutils/PromiseOrValue'; import inspect from '../jsutils/inspect'; import memoize3 from '../jsutils/memoize3'; import invariant from '../jsutils/invariant'; @@ -12,11 +12,11 @@ import promiseReduce from '../jsutils/promiseReduce'; import promiseForObject from '../jsutils/promiseForObject'; import { addPath, pathToArray } from '../jsutils/Path'; -import type { GraphQLFormattedError } from '../error/formatError'; +import { GraphQLFormattedError } from '../error/formatError'; import { GraphQLError } from '../error/GraphQLError'; import { locatedError } from '../error/locatedError'; -import type { +import { DocumentNode, OperationDefinitionNode, SelectionSetNode, @@ -27,8 +27,8 @@ import type { } from '../language/ast'; import { Kind } from '../language/kinds'; -import type { GraphQLSchema } from '../type/schema'; -import type { +import { GraphQLSchema } from '../type/schema'; +import { GraphQLObjectType, GraphQLOutputType, GraphQLLeafType, @@ -92,17 +92,19 @@ import { * Namely, schema of the type system that is currently executing, * and the fragments defined in the query document */ -export type ExecutionContext = {| - schema: GraphQLSchema, - fragments: ObjMap, - rootValue: mixed, - contextValue: mixed, - operation: OperationDefinitionNode, - variableValues: { [variable: string]: mixed, ... }, - fieldResolver: GraphQLFieldResolver, - typeResolver: GraphQLTypeResolver, - errors: Array, -|}; +export type ExecutionContext = { + schema: GraphQLSchema; + fragments: ObjMap; + rootValue: unknown; + contextValue: unknown; + operation: OperationDefinitionNode; + variableValues: { + [variable: string]: unknown; + }; + fieldResolver: GraphQLFieldResolver; + typeResolver: GraphQLTypeResolver; + errors: Array; +}; /** * The result of GraphQL execution. @@ -111,28 +113,33 @@ export type ExecutionContext = {| * - `data` is the result of a successful execution of the query. * - `extensions` is reserved for adding non-standard properties. */ -export type ExecutionResult = {| - errors?: $ReadOnlyArray, - data?: ObjMap | null, - extensions?: ObjMap, -|}; - -export type FormattedExecutionResult = {| - errors?: $ReadOnlyArray, - data?: ObjMap | null, - extensions?: ObjMap, -|}; - -export type ExecutionArgs = {| - schema: GraphQLSchema, - document: DocumentNode, - rootValue?: mixed, - contextValue?: mixed, - variableValues?: ?{ +[variable: string]: mixed, ... }, - operationName?: ?string, - fieldResolver?: ?GraphQLFieldResolver, - typeResolver?: ?GraphQLTypeResolver, -|}; +export type ExecutionResult = { + errors?: ReadonlyArray; + data?: ObjMap | null; + extensions?: ObjMap; +}; + +export type FormattedExecutionResult = { + errors?: ReadonlyArray; + data?: ObjMap | null; + extensions?: ObjMap; +}; + +export type ExecutionArgs = { + schema: GraphQLSchema; + document: DocumentNode; + rootValue?: unknown; + contextValue?: unknown; + variableValues?: + | { + readonly [variable: string]: unknown; + } + | null + | undefined; + operationName?: string | null | undefined; + fieldResolver?: GraphQLFieldResolver | null | undefined; + typeResolver?: GraphQLTypeResolver | null | undefined; +}; /** * Implements the "Evaluating requests" section of the GraphQL specification. @@ -210,7 +217,7 @@ export function executeSync(args: ExecutionArgs): ExecutionResult { */ function buildResponse( exeContext: ExecutionContext, - data: PromiseOrValue | null>, + data: PromiseOrValue | null>, ): PromiseOrValue { if (isPromise(data)) { return data.then((resolved) => buildResponse(exeContext, resolved)); @@ -229,7 +236,12 @@ function buildResponse( export function assertValidExecutionArguments( schema: GraphQLSchema, document: DocumentNode, - rawVariableValues: ?{ +[variable: string]: mixed, ... }, + rawVariableValues: + | { + readonly [variable: string]: unknown; + } + | null + | undefined, ): void { devAssert(document, 'Must provide document.'); @@ -254,13 +266,18 @@ export function assertValidExecutionArguments( export function buildExecutionContext( schema: GraphQLSchema, document: DocumentNode, - rootValue: mixed, - contextValue: mixed, - rawVariableValues: ?{ +[variable: string]: mixed, ... }, - operationName: ?string, - fieldResolver: ?GraphQLFieldResolver, - typeResolver?: ?GraphQLTypeResolver, -): $ReadOnlyArray | ExecutionContext { + rootValue: unknown, + contextValue: unknown, + rawVariableValues: + | { + readonly [variable: string]: unknown; + } + | null + | undefined, + operationName: string | null | undefined, + fieldResolver: GraphQLFieldResolver | null | undefined, + typeResolver?: GraphQLTypeResolver | null | undefined, +): ReadonlyArray | ExecutionContext { let operation: OperationDefinitionNode | void; const fragments: ObjMap = Object.create(null); for (const definition of document.definitions) { @@ -278,6 +295,7 @@ export function buildExecutionContext( } else if (definition.name?.value === operationName) { operation = definition; } + break; case Kind.FRAGMENT_DEFINITION: fragments[definition.name.value] = definition; @@ -325,8 +343,8 @@ export function buildExecutionContext( function executeOperation( exeContext: ExecutionContext, operation: OperationDefinitionNode, - rootValue: mixed, -): PromiseOrValue | null> { + rootValue: unknown, +): PromiseOrValue | null> { const type = getOperationRootType(exeContext.schema, operation); const fields = collectFields( exeContext, @@ -366,10 +384,10 @@ function executeOperation( function executeFieldsSerially( exeContext: ExecutionContext, parentType: GraphQLObjectType, - sourceValue: mixed, + sourceValue: unknown, path: Path | void, fields: ObjMap>, -): PromiseOrValue> { +): PromiseOrValue> { return promiseReduce( Object.keys(fields), (results, responseName) => { @@ -405,10 +423,10 @@ function executeFieldsSerially( function executeFields( exeContext: ExecutionContext, parentType: GraphQLObjectType, - sourceValue: mixed, + sourceValue: unknown, path: Path | void, fields: ObjMap>, -): PromiseOrValue> { +): PromiseOrValue> { const results = Object.create(null); let containsPromise = false; @@ -584,10 +602,10 @@ function getFieldEntryKey(node: FieldNode): string { function resolveField( exeContext: ExecutionContext, parentType: GraphQLObjectType, - source: mixed, - fieldNodes: $ReadOnlyArray, + source: unknown, + fieldNodes: ReadonlyArray, path: Path, -): PromiseOrValue { +): PromiseOrValue { const fieldNode = fieldNodes[0]; const fieldName = fieldNode.name.value; @@ -661,8 +679,8 @@ function resolveField( */ export function buildResolveInfo( exeContext: ExecutionContext, - fieldDef: GraphQLField, - fieldNodes: $ReadOnlyArray, + fieldDef: GraphQLField, + fieldNodes: ReadonlyArray, parentType: GraphQLObjectType, path: Path, ): GraphQLResolveInfo { @@ -723,11 +741,11 @@ function handleFieldError( function completeValue( exeContext: ExecutionContext, returnType: GraphQLOutputType, - fieldNodes: $ReadOnlyArray, + fieldNodes: ReadonlyArray, info: GraphQLResolveInfo, path: Path, - result: mixed, -): PromiseOrValue { + result: unknown, +): PromiseOrValue { // If result is an Error, throw a located error. if (result instanceof Error) { throw result; @@ -805,7 +823,7 @@ function completeValue( invariant( false, 'Cannot complete value of unexpected output type: ' + - inspect((returnType: empty)), + inspect(returnType as never), ); } @@ -816,11 +834,11 @@ function completeValue( function completeListValue( exeContext: ExecutionContext, returnType: GraphQLList, - fieldNodes: $ReadOnlyArray, + fieldNodes: ReadonlyArray, info: GraphQLResolveInfo, path: Path, - result: mixed, -): PromiseOrValue<$ReadOnlyArray> { + result: unknown, +): PromiseOrValue> { if (!isCollection(result)) { throw new GraphQLError( `Expected Iterable, but did not find one for field "${info.parentType.name}.${info.fieldName}".`, @@ -886,7 +904,10 @@ function completeListValue( * Complete a Scalar or Enum by serializing to a valid value, returning * null if serialization is not possible. */ -function completeLeafValue(returnType: GraphQLLeafType, result: mixed): mixed { +function completeLeafValue( + returnType: GraphQLLeafType, + result: unknown, +): unknown { const serializedResult = returnType.serialize(result); if (serializedResult === undefined) { throw new Error( @@ -904,11 +925,11 @@ function completeLeafValue(returnType: GraphQLLeafType, result: mixed): mixed { function completeAbstractValue( exeContext: ExecutionContext, returnType: GraphQLAbstractType, - fieldNodes: $ReadOnlyArray, + fieldNodes: ReadonlyArray, info: GraphQLResolveInfo, path: Path, - result: mixed, -): PromiseOrValue> { + result: unknown, +): PromiseOrValue> { const resolveTypeFn = returnType.resolveType ?? exeContext.typeResolver; const contextValue = exeContext.contextValue; const runtimeType = resolveTypeFn(result, contextValue, info, returnType); @@ -951,12 +972,12 @@ function completeAbstractValue( } function ensureValidRuntimeType( - runtimeTypeName: mixed, + runtimeTypeName: unknown, exeContext: ExecutionContext, returnType: GraphQLAbstractType, - fieldNodes: $ReadOnlyArray, + fieldNodes: ReadonlyArray, info: GraphQLResolveInfo, - result: mixed, + result: unknown, ): GraphQLObjectType { if (runtimeTypeName == null) { throw new GraphQLError( @@ -1011,11 +1032,11 @@ function ensureValidRuntimeType( function completeObjectValue( exeContext: ExecutionContext, returnType: GraphQLObjectType, - fieldNodes: $ReadOnlyArray, + fieldNodes: ReadonlyArray, info: GraphQLResolveInfo, path: Path, - result: mixed, -): PromiseOrValue> { + result: unknown, +): PromiseOrValue> { // If there is an isTypeOf predicate function, call it with the // current result. If isTypeOf returns false, then raise an error rather // than continuing execution. @@ -1053,8 +1074,8 @@ function completeObjectValue( function invalidReturnTypeError( returnType: GraphQLObjectType, - result: mixed, - fieldNodes: $ReadOnlyArray, + result: unknown, + fieldNodes: ReadonlyArray, ): GraphQLError { return new GraphQLError( `Expected value of type "${returnType.name}" but got: ${inspect(result)}.`, @@ -1065,10 +1086,10 @@ function invalidReturnTypeError( function collectAndExecuteSubfields( exeContext: ExecutionContext, returnType: GraphQLObjectType, - fieldNodes: $ReadOnlyArray, + fieldNodes: ReadonlyArray, path: Path, - result: mixed, -): PromiseOrValue> { + result: unknown, +): PromiseOrValue> { // Collect sub-fields to execute to complete this value. const subFieldNodes = collectSubfields(exeContext, returnType, fieldNodes); return executeFields(exeContext, returnType, result, path, subFieldNodes); @@ -1083,7 +1104,7 @@ const collectSubfields = memoize3(_collectSubfields); function _collectSubfields( exeContext: ExecutionContext, returnType: GraphQLObjectType, - fieldNodes: $ReadOnlyArray, + fieldNodes: ReadonlyArray, ): ObjMap> { let subFieldNodes = Object.create(null); const visitedFragmentNames = Object.create(null); @@ -1111,12 +1132,10 @@ function _collectSubfields( * Otherwise, test each possible type for the abstract type by calling * isTypeOf for the object being coerced, returning the first type that matches. */ -export const defaultTypeResolver: GraphQLTypeResolver = function ( - value, - contextValue, - info, - abstractType, -) { +export const defaultTypeResolver: GraphQLTypeResolver< + unknown, + unknown +> = function (value, contextValue, info, abstractType) { // First, look for `__typename`. if (isObjectLike(value) && typeof value.__typename === 'string') { return value.__typename; @@ -1158,8 +1177,8 @@ export const defaultTypeResolver: GraphQLTypeResolver = function ( * of calling that function while passing along args and context value. */ export const defaultFieldResolver: GraphQLFieldResolver< - mixed, - mixed, + unknown, + unknown > = function (source: any, args, contextValue, info) { // ensure source is a value for which property access is acceptable. if (isObjectLike(source) || typeof source === 'function') { @@ -1186,7 +1205,7 @@ export function getFieldDef( schema: GraphQLSchema, parentType: GraphQLObjectType, fieldName: string, -): ?GraphQLField { +): GraphQLField | null | undefined { if ( fieldName === SchemaMetaFieldDef.name && schema.getQueryType() === parentType diff --git a/src/execution/index.js b/src/execution/index.ts similarity index 95% rename from src/execution/index.js rename to src/execution/index.ts index 5ae0706ec95..f7812501ccd 100644 --- a/src/execution/index.js +++ b/src/execution/index.ts @@ -7,7 +7,7 @@ export { defaultTypeResolver, } from './execute'; -export type { +export { ExecutionArgs, ExecutionResult, FormattedExecutionResult, diff --git a/src/execution/values.js b/src/execution/values.ts similarity index 87% rename from src/execution/values.js rename to src/execution/values.ts index 51c06780985..f7accac8d18 100644 --- a/src/execution/values.js +++ b/src/execution/values.ts @@ -1,11 +1,11 @@ -import type { ObjMap } from '../jsutils/ObjMap'; +import { ObjMap } from '../jsutils/ObjMap'; import keyMap from '../jsutils/keyMap'; import inspect from '../jsutils/inspect'; import printPathArray from '../jsutils/printPathArray'; import { GraphQLError } from '../error/GraphQLError'; -import type { +import { FieldNode, DirectiveNode, VariableDefinitionNode, @@ -13,9 +13,9 @@ import type { import { Kind } from '../language/kinds'; import { print } from '../language/printer'; -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLField } from '../type/definition'; -import type { GraphQLDirective } from '../type/directives'; +import { GraphQLSchema } from '../type/schema'; +import { GraphQLField } from '../type/definition'; +import { GraphQLDirective } from '../type/directives'; import { isInputType, isNonNullType } from '../type/definition'; import { typeFromAST } from '../utilities/typeFromAST'; @@ -23,8 +23,12 @@ import { valueFromAST } from '../utilities/valueFromAST'; import { coerceInputValue } from '../utilities/coerceInputValue'; type CoercedVariableValues = - | {| errors: $ReadOnlyArray |} - | {| coerced: { [variable: string]: mixed, ... } |}; + | { errors: ReadonlyArray } + | { + coerced: { + [variable: string]: unknown; + }; + }; /** * Prepares an object map of variableValues of the correct type based on the @@ -39,9 +43,11 @@ type CoercedVariableValues = */ export function getVariableValues( schema: GraphQLSchema, - varDefNodes: $ReadOnlyArray, - inputs: { +[variable: string]: mixed, ... }, - options?: {| maxErrors?: number |}, + varDefNodes: ReadonlyArray, + inputs: { + readonly [variable: string]: unknown; + }, + options?: { maxErrors?: number }, ): CoercedVariableValues { const errors = []; const maxErrors = options?.maxErrors; @@ -72,10 +78,14 @@ export function getVariableValues( function coerceVariableValues( schema: GraphQLSchema, - varDefNodes: $ReadOnlyArray, - inputs: { +[variable: string]: mixed, ... }, - onError: (GraphQLError) => void, -): { [variable: string]: mixed, ... } { + varDefNodes: ReadonlyArray, + inputs: { + readonly [variable: string]: unknown; + }, + onError: (arg0: GraphQLError) => void, +): { + [variable: string]: unknown; +} { const coercedValues = {}; for (const varDefNode of varDefNodes) { const varName = varDefNode.variable.name.value; @@ -157,10 +167,12 @@ function coerceVariableValues( * @internal */ export function getArgumentValues( - def: GraphQLField | GraphQLDirective, + def: GraphQLField | GraphQLDirective, node: FieldNode | DirectiveNode, - variableValues?: ?ObjMap, -): { [argument: string]: mixed, ... } { + variableValues?: ObjMap | null | undefined, +): { + [argument: string]: unknown; +} { const coercedValues = {}; // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') @@ -244,9 +256,11 @@ export function getArgumentValues( */ export function getDirectiveValues( directiveDef: GraphQLDirective, - node: { +directives?: $ReadOnlyArray, ... }, - variableValues?: ?ObjMap, -): void | { [argument: string]: mixed, ... } { + node: { readonly directives?: ReadonlyArray }, + variableValues?: ObjMap | null | undefined, +): void | { + [argument: string]: unknown; +} { // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const directiveNode = node.directives?.find( (directive) => directive.name.value === directiveDef.name, @@ -257,6 +271,6 @@ export function getDirectiveValues( } } -function hasOwnProperty(obj: mixed, prop: string): boolean { +function hasOwnProperty(obj: unknown, prop: string): boolean { return Object.prototype.hasOwnProperty.call(obj, prop); } diff --git a/src/graphql.js b/src/graphql.ts similarity index 84% rename from src/graphql.js rename to src/graphql.ts index 622be10cd54..38e65c5c8f9 100644 --- a/src/graphql.js +++ b/src/graphql.ts @@ -1,19 +1,16 @@ -import type { PromiseOrValue } from './jsutils/PromiseOrValue'; +import { PromiseOrValue } from './jsutils/PromiseOrValue'; import isPromise from './jsutils/isPromise'; -import type { Source } from './language/source'; +import { Source } from './language/source'; import { parse } from './language/parser'; import { validate } from './validation/validate'; -import type { - GraphQLFieldResolver, - GraphQLTypeResolver, -} from './type/definition'; -import type { GraphQLSchema } from './type/schema'; +import { GraphQLFieldResolver, GraphQLTypeResolver } from './type/definition'; +import { GraphQLSchema } from './type/schema'; import { validateSchema } from './type/validate'; -import type { ExecutionResult } from './execution/execute'; +import { ExecutionResult } from './execution/execute'; import { execute } from './execution/execute'; /** @@ -55,16 +52,21 @@ import { execute } from './execution/execute'; * If not provided, the default type resolver is used (which looks for a * `__typename` field or alternatively calls the `isTypeOf` method). */ -export type GraphQLArgs = {| - schema: GraphQLSchema, - source: string | Source, - rootValue?: mixed, - contextValue?: mixed, - variableValues?: ?{ +[variable: string]: mixed, ... }, - operationName?: ?string, - fieldResolver?: ?GraphQLFieldResolver, - typeResolver?: ?GraphQLTypeResolver, -|}; +export type GraphQLArgs = { + schema: GraphQLSchema; + source: string | Source; + rootValue?: unknown; + contextValue?: unknown; + variableValues?: + | { + readonly [variable: string]: unknown; + } + | null + | undefined; + operationName?: string | null | undefined; + fieldResolver?: GraphQLFieldResolver | null | undefined; + typeResolver?: GraphQLTypeResolver | null | undefined; +}; export function graphql(args: GraphQLArgs): Promise { // Always return a Promise for a consistent API. diff --git a/src/index.js b/src/index.ts similarity index 71% rename from src/index.js rename to src/index.ts index 873a374ba2e..0907f72d02b 100644 --- a/src/index.js +++ b/src/index.ts @@ -26,7 +26,7 @@ export { version, versionInfo } from './version'; // The primary entry point into fulfilling a GraphQL request. -export type { GraphQLArgs } from './graphql'; +export { GraphQLArgs } from './graphql'; export { graphql, graphqlSync } from './graphql'; // Create and operate on GraphQL type definitions and schema. @@ -41,25 +41,20 @@ export { GraphQLEnumType, GraphQLInputObjectType, GraphQLList, - GraphQLNonNull, - // Standard GraphQL Scalars + GraphQLNonNull, // Standard GraphQL Scalars specifiedScalarTypes, GraphQLInt, GraphQLFloat, GraphQLString, GraphQLBoolean, - GraphQLID, - // Built-in Directives defined by the Spec + GraphQLID, // Built-in Directives defined by the Spec specifiedDirectives, GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, - GraphQLSpecifiedByDirective, - // "Enum" of Type Kinds - TypeKind, - // Constant Deprecation Reason - DEFAULT_DEPRECATION_REASON, - // GraphQL Types for introspection. + GraphQLSpecifiedByDirective, // "Enum" of Type Kinds + TypeKind, // Constant Deprecation Reason + DEFAULT_DEPRECATION_REASON, // GraphQL Types for introspection. introspectionTypes, __Schema, __Directive, @@ -68,12 +63,10 @@ export { __Field, __InputValue, __EnumValue, - __TypeKind, - // Meta-field definitions. + __TypeKind, // Meta-field definitions. SchemaMetaFieldDef, TypeMetaFieldDef, - TypeNameMetaFieldDef, - // Predicates + TypeNameMetaFieldDef, // Predicates isSchema, isDirective, isType, @@ -97,8 +90,7 @@ export { isRequiredInputField, isSpecifiedScalarType, isIntrospectionType, - isSpecifiedDirective, - // Assertions + isSpecifiedDirective, // Assertions assertSchema, assertDirective, assertType, @@ -117,16 +109,14 @@ export { assertAbstractType, assertWrappingType, assertNullableType, - assertNamedType, - // Un-modifiers + assertNamedType, // Un-modifiers getNullableType, - getNamedType, - // Validate GraphQL schema. + getNamedType, // Validate GraphQL schema. validateSchema, assertValidSchema, } from './type/index'; -export type { +export { GraphQLType, GraphQLInputType, GraphQLOutputType, @@ -174,27 +164,21 @@ export { Token, Source, Location, - getLocation, - // Print source location + getLocation, // Print source location printLocation, - printSourceLocation, - // Lex + printSourceLocation, // Lex Lexer, - TokenKind, - // Parse + TokenKind, // Parse parse, parseValue, - parseType, - // Print - print, - // Visit + parseType, // Print + print, // Visit visit, visitInParallel, getVisitFn, BREAK, Kind, - DirectiveLocation, - // Predicates + DirectiveLocation, // Predicates isDefinitionNode, isExecutableDefinitionNode, isSelectionNode, @@ -206,21 +190,18 @@ export { isTypeExtensionNode, } from './language/index'; -export type { +export { ParseOptions, SourceLocation, TokenKindEnum, KindEnum, - DirectiveLocationEnum, - // Visitor utilities + DirectiveLocationEnum, // Visitor utilities ASTVisitor, Visitor, VisitFn, - VisitorKeyMap, - // AST nodes + VisitorKeyMap, // AST nodes ASTNode, - ASTKindToNode, - // Each kind of AST node + ASTKindToNode, // Each kind of AST node NameNode, DocumentNode, DefinitionNode, @@ -286,22 +267,20 @@ export { getDirectiveValues, } from './execution/index'; -export type { +export { ExecutionArgs, ExecutionResult, FormattedExecutionResult, } from './execution/index'; export { subscribe, createSourceEventStream } from './subscription/index'; -export type { SubscriptionArgs } from './subscription/index'; +export { SubscriptionArgs } from './subscription/index'; // Validate GraphQL documents. export { validate, - ValidationContext, - // All validation rules in the GraphQL Specification. - specifiedRules, - // Individual validation rules. + ValidationContext, // All validation rules in the GraphQL Specification. + specifiedRules, // Individual validation rules. ExecutableDefinitionsRule, FieldsOnCorrectTypeRule, FragmentsOnCompositeTypesRule, @@ -327,21 +306,19 @@ export { UniqueVariableNamesRule, ValuesOfCorrectTypeRule, VariablesAreInputTypesRule, - VariablesInAllowedPositionRule, - // SDL-specific validation rules + VariablesInAllowedPositionRule, // SDL-specific validation rules LoneSchemaDefinitionRule, UniqueOperationTypesRule, UniqueTypeNamesRule, UniqueEnumValueNamesRule, UniqueFieldDefinitionNamesRule, UniqueDirectiveNamesRule, - PossibleTypeExtensionsRule, - // Custom validation rules + PossibleTypeExtensionsRule, // Custom validation rules NoDeprecatedCustomRule, NoSchemaIntrospectionCustomRule, } from './validation/index'; -export type { ValidationRule } from './validation/index'; +export { ValidationRule } from './validation/index'; // Create, format, and print GraphQL errors. export { @@ -352,74 +329,50 @@ export { formatError, } from './error/index'; -export type { GraphQLFormattedError } from './error/index'; +export { GraphQLFormattedError } from './error/index'; // Utilities for operating on GraphQL type schema and parsed sources. export { // Produce the GraphQL query recommended for a full schema introspection. // Accepts optional IntrospectionOptions. - getIntrospectionQuery, - // Gets the target Operation from a Document. - getOperationAST, - // Gets the Type for the target Operation AST. - getOperationRootType, - // Convert a GraphQLSchema to an IntrospectionQuery. - introspectionFromSchema, - // Build a GraphQLSchema from an introspection result. - buildClientSchema, - // Build a GraphQLSchema from a parsed GraphQL Schema language AST. - buildASTSchema, - // Build a GraphQLSchema from a GraphQL schema language document. - buildSchema, - // Extends an existing GraphQLSchema from a parsed GraphQL Schema + getIntrospectionQuery, // Gets the target Operation from a Document. + getOperationAST, // Gets the Type for the target Operation AST. + getOperationRootType, // Convert a GraphQLSchema to an IntrospectionQuery. + introspectionFromSchema, // Build a GraphQLSchema from an introspection result. + buildClientSchema, // Build a GraphQLSchema from a parsed GraphQL Schema language AST. + buildASTSchema, // Build a GraphQLSchema from a GraphQL schema language document. + buildSchema, // Extends an existing GraphQLSchema from a parsed GraphQL Schema // language AST. - extendSchema, - // Sort a GraphQLSchema. - lexicographicSortSchema, - // Print a GraphQLSchema to GraphQL Schema language. - printSchema, - // Print a GraphQLType to GraphQL Schema language. - printType, - // Prints the built-in introspection schema in the Schema Language + extendSchema, // Sort a GraphQLSchema. + lexicographicSortSchema, // Print a GraphQLSchema to GraphQL Schema language. + printSchema, // Print a GraphQLType to GraphQL Schema language. + printType, // Prints the built-in introspection schema in the Schema Language // format. - printIntrospectionSchema, - // Create a GraphQLType from a GraphQL language AST. - typeFromAST, - // Create a JavaScript value from a GraphQL language AST with a Type. - valueFromAST, - // Create a JavaScript value from a GraphQL language AST without a Type. - valueFromASTUntyped, - // Create a GraphQL language AST from a JavaScript value. - astFromValue, - // A helper to use within recursive-descent visitors which need to be aware of + printIntrospectionSchema, // Create a GraphQLType from a GraphQL language AST. + typeFromAST, // Create a JavaScript value from a GraphQL language AST with a Type. + valueFromAST, // Create a JavaScript value from a GraphQL language AST without a Type. + valueFromASTUntyped, // Create a GraphQL language AST from a JavaScript value. + astFromValue, // A helper to use within recursive-descent visitors which need to be aware of // the GraphQL type system. TypeInfo, - visitWithTypeInfo, - // Coerces a JavaScript value to a GraphQL type, or produces errors. - coerceInputValue, - // Concatenates multiple AST together. - concatAST, - // Separates an AST into an AST per Operation. - separateOperations, - // Strips characters that are not significant to the validity or execution + visitWithTypeInfo, // Coerces a JavaScript value to a GraphQL type, or produces errors. + coerceInputValue, // Concatenates multiple AST together. + concatAST, // Separates an AST into an AST per Operation. + separateOperations, // Strips characters that are not significant to the validity or execution // of a GraphQL document. - stripIgnoredCharacters, - // Comparators for types + stripIgnoredCharacters, // Comparators for types isEqualType, isTypeSubTypeOf, - doTypesOverlap, - // Asserts a string is a valid GraphQL name. - assertValidName, - // Determine if a string is a valid GraphQL name. - isValidNameError, - // Compares two GraphQLSchemas and detects breaking changes. + doTypesOverlap, // Asserts a string is a valid GraphQL name. + assertValidName, // Determine if a string is a valid GraphQL name. + isValidNameError, // Compares two GraphQLSchemas and detects breaking changes. BreakingChangeType, DangerousChangeType, findBreakingChanges, findDangerousChanges, } from './utilities/index'; -export type { +export { IntrospectionOptions, IntrospectionQuery, IntrospectionSchema, diff --git a/src/jsutils/ObjMap.js b/src/jsutils/ObjMap.js deleted file mode 100644 index 9b6ef5e16e5..00000000000 --- a/src/jsutils/ObjMap.js +++ /dev/null @@ -1,7 +0,0 @@ -export type ObjMap = { [key: string]: T, __proto__: null, ... }; -export type ObjMapLike = ObjMap | { [key: string]: T, ... }; - -export type ReadOnlyObjMap = { +[key: string]: T, __proto__: null, ... }; -export type ReadOnlyObjMapLike = - | ReadOnlyObjMap - | { +[key: string]: T, ... }; diff --git a/src/jsutils/ObjMap.ts b/src/jsutils/ObjMap.ts new file mode 100644 index 00000000000..07330fc8341 --- /dev/null +++ b/src/jsutils/ObjMap.ts @@ -0,0 +1,13 @@ +export type ObjMap = { __proto__: null; [key: string]: T }; +export type ObjMapLike = + | ObjMap + | { + [key: string]: T; + }; + +export type ReadOnlyObjMap = { __proto__: null; readonly [key: string]: T }; +export type ReadOnlyObjMapLike = + | ReadOnlyObjMap + | { + readonly [key: string]: T; + }; diff --git a/src/jsutils/Path.js b/src/jsutils/Path.ts similarity index 62% rename from src/jsutils/Path.js rename to src/jsutils/Path.ts index 47e8c7693ca..0703b6bf9bf 100644 --- a/src/jsutils/Path.js +++ b/src/jsutils/Path.ts @@ -1,8 +1,9 @@ -export type Path = {| - +prev: Path | void, - +key: string | number, - +typename: string | void, -|}; +import { $ReadOnly } from 'utility-types'; +export type Path = { + readonly prev: Path | void; + readonly key: string | number; + readonly typename: string | void; +}; /** * Given a Path and a key, return a new Path containing the new key. @@ -18,7 +19,9 @@ export function addPath( /** * Given a Path, return an Array of the path keys. */ -export function pathToArray(path: ?$ReadOnly): Array { +export function pathToArray( + path: $ReadOnly | null | undefined, +): Array { const flattened = []; let curr = path; while (curr) { diff --git a/src/jsutils/PromiseOrValue.js b/src/jsutils/PromiseOrValue.js deleted file mode 100644 index e493c87e061..00000000000 --- a/src/jsutils/PromiseOrValue.js +++ /dev/null @@ -1 +0,0 @@ -export type PromiseOrValue<+T> = Promise | T; diff --git a/src/jsutils/PromiseOrValue.ts b/src/jsutils/PromiseOrValue.ts new file mode 100644 index 00000000000..6b2517ee625 --- /dev/null +++ b/src/jsutils/PromiseOrValue.ts @@ -0,0 +1 @@ +export type PromiseOrValue = Promise | T; diff --git a/src/jsutils/__tests__/didYouMean-test.js b/src/jsutils/__tests__/didYouMean-test.ts similarity index 100% rename from src/jsutils/__tests__/didYouMean-test.js rename to src/jsutils/__tests__/didYouMean-test.ts diff --git a/src/jsutils/__tests__/identityFunc-test.js b/src/jsutils/__tests__/identityFunc-test.ts similarity index 100% rename from src/jsutils/__tests__/identityFunc-test.js rename to src/jsutils/__tests__/identityFunc-test.ts diff --git a/src/jsutils/__tests__/inspect-test.js b/src/jsutils/__tests__/inspect-test.ts similarity index 98% rename from src/jsutils/__tests__/inspect-test.js rename to src/jsutils/__tests__/inspect-test.ts index ba7ca9a86cb..7b48339c3e6 100644 --- a/src/jsutils/__tests__/inspect-test.js +++ b/src/jsutils/__tests__/inspect-test.ts @@ -166,7 +166,7 @@ describe('inspect', () => { expect(inspect([[new Foo()]])).to.equal('[[[Foo]]]'); - (Foo.prototype: any)[Symbol.toStringTag] = 'Bar'; + (Foo.prototype as any)[Symbol.toStringTag] = 'Bar'; expect(inspect([[new Foo()]])).to.equal('[[[Bar]]]'); const objectWithoutClassName = new (function () { diff --git a/src/jsutils/__tests__/instanceOf-test.js b/src/jsutils/__tests__/instanceOf-test.ts similarity index 100% rename from src/jsutils/__tests__/instanceOf-test.js rename to src/jsutils/__tests__/instanceOf-test.ts diff --git a/src/jsutils/__tests__/invariant-test.js b/src/jsutils/__tests__/invariant-test.ts similarity index 100% rename from src/jsutils/__tests__/invariant-test.js rename to src/jsutils/__tests__/invariant-test.ts diff --git a/src/jsutils/__tests__/isAsyncIterable-test.js b/src/jsutils/__tests__/isAsyncIterable-test.ts similarity index 100% rename from src/jsutils/__tests__/isAsyncIterable-test.js rename to src/jsutils/__tests__/isAsyncIterable-test.ts diff --git a/src/jsutils/__tests__/isCollection-test.js b/src/jsutils/__tests__/isCollection-test.ts similarity index 100% rename from src/jsutils/__tests__/isCollection-test.js rename to src/jsutils/__tests__/isCollection-test.ts diff --git a/src/jsutils/__tests__/isObjectLike-test.js b/src/jsutils/__tests__/isObjectLike-test.ts similarity index 100% rename from src/jsutils/__tests__/isObjectLike-test.js rename to src/jsutils/__tests__/isObjectLike-test.ts diff --git a/src/jsutils/__tests__/suggestionList-test.js b/src/jsutils/__tests__/suggestionList-test.ts similarity index 100% rename from src/jsutils/__tests__/suggestionList-test.js rename to src/jsutils/__tests__/suggestionList-test.ts diff --git a/src/jsutils/__tests__/toObjMap-test.js b/src/jsutils/__tests__/toObjMap-test.ts similarity index 96% rename from src/jsutils/__tests__/toObjMap-test.js rename to src/jsutils/__tests__/toObjMap-test.ts index 3f5ab924f55..faab3caef5d 100644 --- a/src/jsutils/__tests__/toObjMap-test.js +++ b/src/jsutils/__tests__/toObjMap-test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import type { ObjMapLike } from '../ObjMap'; +import { ObjMapLike } from '../ObjMap'; import toObjMap from '../toObjMap'; // Workaround to make both ESLint and Flow happy diff --git a/src/jsutils/devAssert.js b/src/jsutils/devAssert.ts similarity index 71% rename from src/jsutils/devAssert.js rename to src/jsutils/devAssert.ts index da2adfcd001..f8364cee320 100644 --- a/src/jsutils/devAssert.js +++ b/src/jsutils/devAssert.ts @@ -1,4 +1,4 @@ -export default function devAssert(condition: mixed, message: string): void { +export default function devAssert(condition: unknown, message: string): void { const booleanCondition = Boolean(condition); // istanbul ignore else (See transformation done in './resources/inlineInvariant.js') if (!booleanCondition) { diff --git a/src/jsutils/didYouMean.js b/src/jsutils/didYouMean.ts similarity index 89% rename from src/jsutils/didYouMean.js rename to src/jsutils/didYouMean.ts index 45e1a93c831..63bfbf823bd 100644 --- a/src/jsutils/didYouMean.js +++ b/src/jsutils/didYouMean.ts @@ -3,11 +3,11 @@ const MAX_SUGGESTIONS = 5; /** * Given [ A, B, C ] return ' Did you mean A, B, or C?'. */ -declare function didYouMean(suggestions: $ReadOnlyArray): string; +declare function didYouMean(suggestions: ReadonlyArray): string; // eslint-disable-next-line no-redeclare declare function didYouMean( subMessage: string, - suggestions: $ReadOnlyArray, + suggestions: ReadonlyArray, ): string; // eslint-disable-next-line no-redeclare diff --git a/src/jsutils/identityFunc.js b/src/jsutils/identityFunc.ts similarity index 100% rename from src/jsutils/identityFunc.js rename to src/jsutils/identityFunc.ts diff --git a/src/jsutils/inspect.js b/src/jsutils/inspect.ts similarity index 87% rename from src/jsutils/inspect.js rename to src/jsutils/inspect.ts index f841f7da8d3..728023d9d9f 100644 --- a/src/jsutils/inspect.js +++ b/src/jsutils/inspect.ts @@ -6,11 +6,11 @@ const MAX_RECURSIVE_DEPTH = 2; /** * Used to print values in error messages. */ -export default function inspect(value: mixed): string { +export default function inspect(value: unknown): string { return formatValue(value, []); } -function formatValue(value: mixed, seenValues: Array): string { +function formatValue(value: unknown, seenValues: Array): string { switch (typeof value) { case 'string': return JSON.stringify(value); @@ -20,6 +20,7 @@ function formatValue(value: mixed, seenValues: Array): string { if (value === null) { return 'null'; } + return formatObjectValue(value, seenValues); default: return String(value); @@ -28,7 +29,7 @@ function formatValue(value: mixed, seenValues: Array): string { function formatObjectValue( value: Object, - previouslySeenValues: Array, + previouslySeenValues: Array, ): string { if (previouslySeenValues.indexOf(value) !== -1) { return '[Circular]'; @@ -52,7 +53,7 @@ function formatObjectValue( return formatObject(value, seenValues); } -function formatObject(object: Object, seenValues: Array): string { +function formatObject(object: Object, seenValues: Array): string { const keys = Object.keys(object); if (keys.length === 0) { return '{}'; @@ -70,7 +71,10 @@ function formatObject(object: Object, seenValues: Array): string { return '{ ' + properties.join(', ') + ' }'; } -function formatArray(array: Array, seenValues: Array): string { +function formatArray( + array: Array, + seenValues: Array, +): string { if (array.length === 0) { return '[]'; } diff --git a/src/jsutils/instanceOf.js b/src/jsutils/instanceOf.ts similarity index 64% rename from src/jsutils/instanceOf.js rename to src/jsutils/instanceOf.ts index e55cd13f730..4aeccf7e6bf 100644 --- a/src/jsutils/instanceOf.js +++ b/src/jsutils/instanceOf.ts @@ -2,21 +2,16 @@ * A replacement for instanceof which includes an error warning when multi-realm * constructors are detected. */ -declare function instanceOf( - value: mixed, - constructor: mixed, -): boolean %checks(value instanceof constructor); +declare function instanceOf(value: unknown, constructor: unknown): boolean; // See: https://expressjs.com/en/advanced/best-practice-performance.html#set-node_env-to-production // See: https://webpack.js.org/guides/production/ -export default process.env.NODE_ENV === 'production' - ? // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') - // eslint-disable-next-line no-shadow - function instanceOf(value: mixed, constructor: mixed): boolean { +export default process.env.NODE_ENV === 'production' // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317') + ? // eslint-disable-next-line no-shadow + function instanceOf(value: unknown, constructor: unknown): boolean { return value instanceof constructor; - } - : // eslint-disable-next-line no-shadow - function instanceOf(value: any, constructor: any): boolean { + } // eslint-disable-next-line no-shadow + : function instanceOf(value: any, constructor: any): boolean { if (value instanceof constructor) { return true; } @@ -24,8 +19,7 @@ export default process.env.NODE_ENV === 'production' const valueClass = value.constructor; const className = constructor.name; if (className && valueClass && valueClass.name === className) { - throw new Error( - `Cannot use ${className} "${value}" from another module or realm. + throw new Error(`Cannot use ${className} "${value}" from another module or realm. Ensure that there is only one instance of "graphql" in the node_modules directory. If different versions of "graphql" are the dependencies of other @@ -36,8 +30,7 @@ https://yarnpkg.com/en/docs/selective-version-resolutions Duplicate "graphql" modules cannot be used at the same time since different versions may have different capabilities and behavior. The data from one version used in the function from another could produce confusing and -spurious results.`, - ); +spurious results.`); } } return false; diff --git a/src/jsutils/invariant.js b/src/jsutils/invariant.ts similarity index 76% rename from src/jsutils/invariant.js rename to src/jsutils/invariant.ts index 668f6ea426b..ea99078976d 100644 --- a/src/jsutils/invariant.js +++ b/src/jsutils/invariant.ts @@ -1,4 +1,4 @@ -export default function invariant(condition: mixed, message?: string): void { +export default function invariant(condition: unknown, message?: string): void { const booleanCondition = Boolean(condition); // istanbul ignore else (See transformation done in './resources/inlineInvariant.js') if (!booleanCondition) { diff --git a/src/jsutils/isAsyncIterable.js b/src/jsutils/isAsyncIterable.ts similarity index 81% rename from src/jsutils/isAsyncIterable.js rename to src/jsutils/isAsyncIterable.ts index 39a90bd3468..9bd2900ec4b 100644 --- a/src/jsutils/isAsyncIterable.js +++ b/src/jsutils/isAsyncIterable.ts @@ -2,8 +2,7 @@ * Returns true if the provided object implements the AsyncIterator protocol via * either implementing a `Symbol.asyncIterator` or `"@@asyncIterator"` method. */ -declare function isAsyncIterable(value: mixed): boolean %checks(value instanceof - AsyncIterable); +declare function isAsyncIterable(value: unknown): boolean; // eslint-disable-next-line no-redeclare export default function isAsyncIterable(maybeAsyncIterable) { diff --git a/src/jsutils/isCollection.js b/src/jsutils/isCollection.ts similarity index 92% rename from src/jsutils/isCollection.js rename to src/jsutils/isCollection.ts index b120bda73d4..9956f9160ff 100644 --- a/src/jsutils/isCollection.js +++ b/src/jsutils/isCollection.ts @@ -19,8 +19,7 @@ * An Object value which might implement the Iterable or Array-like protocols. * @return {boolean} true if Iterable or Array-like Object. */ -declare function isCollection(value: mixed): boolean %checks(value instanceof - Iterable); +declare function isCollection(value: unknown): boolean; // eslint-disable-next-line no-redeclare export default function isCollection(obj) { diff --git a/src/jsutils/isObjectLike.js b/src/jsutils/isObjectLike.ts similarity index 72% rename from src/jsutils/isObjectLike.js rename to src/jsutils/isObjectLike.ts index a5f9754dd78..d7c48e39a47 100644 --- a/src/jsutils/isObjectLike.js +++ b/src/jsutils/isObjectLike.ts @@ -2,6 +2,6 @@ * Return true if `value` is object-like. A value is object-like if it's not * `null` and has a `typeof` result of "object". */ -export default function isObjectLike(value: mixed): boolean %checks { +export default function isObjectLike(value: unknown): boolean { return typeof value == 'object' && value !== null; } diff --git a/src/jsutils/isPromise.js b/src/jsutils/isPromise.ts similarity index 73% rename from src/jsutils/isPromise.js rename to src/jsutils/isPromise.ts index 4bbb5768e18..f0df1394563 100644 --- a/src/jsutils/isPromise.js +++ b/src/jsutils/isPromise.ts @@ -2,8 +2,7 @@ * Returns true if the value acts like a Promise, i.e. has a "then" function, * otherwise returns false. */ -declare function isPromise(value: mixed): boolean %checks(value instanceof - Promise); +declare function isPromise(value: unknown): boolean; // eslint-disable-next-line no-redeclare export default function isPromise(value) { diff --git a/src/jsutils/keyMap.js b/src/jsutils/keyMap.ts similarity index 92% rename from src/jsutils/keyMap.js rename to src/jsutils/keyMap.ts index eb847d02c91..670726a1e89 100644 --- a/src/jsutils/keyMap.js +++ b/src/jsutils/keyMap.ts @@ -1,4 +1,4 @@ -import type { ObjMap } from './ObjMap'; +import { ObjMap } from './ObjMap'; /** * Creates a keyed JS object from an array, given a function to produce the keys @@ -24,7 +24,7 @@ import type { ObjMap } from './ObjMap'; * */ export default function keyMap( - list: $ReadOnlyArray, + list: ReadonlyArray, keyFn: (item: T) => string, ): ObjMap { return list.reduce((map, item) => { diff --git a/src/jsutils/keyValMap.js b/src/jsutils/keyValMap.ts similarity index 91% rename from src/jsutils/keyValMap.js rename to src/jsutils/keyValMap.ts index a91e90b447f..b73ad8276d4 100644 --- a/src/jsutils/keyValMap.js +++ b/src/jsutils/keyValMap.ts @@ -1,4 +1,4 @@ -import type { ObjMap } from './ObjMap'; +import { ObjMap } from './ObjMap'; /** * Creates a keyed JS object from an array, given a function to produce the keys @@ -18,7 +18,7 @@ import type { ObjMap } from './ObjMap'; * */ export default function keyValMap( - list: $ReadOnlyArray, + list: ReadonlyArray, keyFn: (item: T) => string, valFn: (item: T) => V, ): ObjMap { diff --git a/src/jsutils/mapValue.js b/src/jsutils/mapValue.ts similarity index 91% rename from src/jsutils/mapValue.js rename to src/jsutils/mapValue.ts index a2b91be2ddd..c0f1cbd7b7e 100644 --- a/src/jsutils/mapValue.js +++ b/src/jsutils/mapValue.ts @@ -1,6 +1,6 @@ import objectEntries from '../polyfills/objectEntries'; -import type { ObjMap } from './ObjMap'; +import { ObjMap } from './ObjMap'; /** * Creates an object map with the same keys as `map` and values generated by diff --git a/src/jsutils/memoize3.js b/src/jsutils/memoize3.ts similarity index 75% rename from src/jsutils/memoize3.js rename to src/jsutils/memoize3.ts index be73a96fb2d..3b62e3e20b6 100644 --- a/src/jsutils/memoize3.js +++ b/src/jsutils/memoize3.ts @@ -2,11 +2,13 @@ * Memoizes the provided three-argument function. */ export default function memoize3< - A1: { ... } | $ReadOnlyArray, - A2: { ... } | $ReadOnlyArray, - A3: { ... } | $ReadOnlyArray, - R: mixed, ->(fn: (A1, A2, A3) => R): (A1, A2, A3) => R { + A1 extends {} | ReadonlyArray, + A2 extends {} | ReadonlyArray, + A3 extends {} | ReadonlyArray, + R extends unknown +>( + fn: (arg0: A1, arg1: A2, arg2: A3) => R, +): (arg0: A1, arg1: A2, arg2: A3) => R { let cache0; return function memoized(a1, a2, a3) { diff --git a/src/jsutils/printPathArray.js b/src/jsutils/printPathArray.ts similarity index 84% rename from src/jsutils/printPathArray.js rename to src/jsutils/printPathArray.ts index 34ab13daa07..fe98a4115e1 100644 --- a/src/jsutils/printPathArray.js +++ b/src/jsutils/printPathArray.ts @@ -2,7 +2,7 @@ * Build a string describing the path. */ export default function printPathArray( - path: $ReadOnlyArray, + path: ReadonlyArray, ): string { return path .map((key) => diff --git a/src/jsutils/promiseForObject.js b/src/jsutils/promiseForObject.ts similarity index 94% rename from src/jsutils/promiseForObject.js rename to src/jsutils/promiseForObject.ts index bf07e4a3f06..e86b08f2b2d 100644 --- a/src/jsutils/promiseForObject.js +++ b/src/jsutils/promiseForObject.ts @@ -1,4 +1,4 @@ -import type { ObjMap } from './ObjMap'; +import { ObjMap } from './ObjMap'; /** * This function transforms a JS object `ObjMap>` into diff --git a/src/jsutils/promiseReduce.js b/src/jsutils/promiseReduce.ts similarity index 82% rename from src/jsutils/promiseReduce.js rename to src/jsutils/promiseReduce.ts index 43d905283ed..a529f44c64c 100644 --- a/src/jsutils/promiseReduce.js +++ b/src/jsutils/promiseReduce.ts @@ -1,4 +1,4 @@ -import type { PromiseOrValue } from './PromiseOrValue'; +import { PromiseOrValue } from './PromiseOrValue'; import isPromise from './isPromise'; @@ -10,8 +10,8 @@ import isPromise from './isPromise'; * return a Promise. */ export default function promiseReduce( - values: $ReadOnlyArray, - callback: (U, T) => PromiseOrValue, + values: ReadonlyArray, + callback: (arg0: U, arg1: T) => PromiseOrValue, initialValue: PromiseOrValue, ): PromiseOrValue { return values.reduce( diff --git a/src/jsutils/suggestionList.js b/src/jsutils/suggestionList.ts similarity index 99% rename from src/jsutils/suggestionList.js rename to src/jsutils/suggestionList.ts index 4128e24b071..d7aa2b6ea98 100644 --- a/src/jsutils/suggestionList.js +++ b/src/jsutils/suggestionList.ts @@ -4,7 +4,7 @@ */ export default function suggestionList( input: string, - options: $ReadOnlyArray, + options: ReadonlyArray, ): Array { const optionsByDistance = Object.create(null); const lexicalDistance = new LexicalDistance(input); diff --git a/src/jsutils/toObjMap.js b/src/jsutils/toObjMap.ts similarity index 97% rename from src/jsutils/toObjMap.js rename to src/jsutils/toObjMap.ts index c0dc9e2fdbc..83cb5e95710 100644 --- a/src/jsutils/toObjMap.js +++ b/src/jsutils/toObjMap.ts @@ -1,6 +1,6 @@ import objectEntries from '../polyfills/objectEntries'; -import type { +import { ObjMap, ObjMapLike, ReadOnlyObjMap, diff --git a/src/language/__tests__/blockString-fuzz.js b/src/language/__tests__/blockString-fuzz.ts similarity index 100% rename from src/language/__tests__/blockString-fuzz.js rename to src/language/__tests__/blockString-fuzz.ts diff --git a/src/language/__tests__/blockString-test.js b/src/language/__tests__/blockString-test.ts similarity index 100% rename from src/language/__tests__/blockString-test.js rename to src/language/__tests__/blockString-test.ts diff --git a/src/language/__tests__/lexer-test.js b/src/language/__tests__/lexer-test.ts similarity index 100% rename from src/language/__tests__/lexer-test.js rename to src/language/__tests__/lexer-test.ts diff --git a/src/language/__tests__/parser-test.js b/src/language/__tests__/parser-test.ts similarity index 100% rename from src/language/__tests__/parser-test.js rename to src/language/__tests__/parser-test.ts diff --git a/src/language/__tests__/predicates-test.js b/src/language/__tests__/predicates-test.ts similarity index 95% rename from src/language/__tests__/predicates-test.js rename to src/language/__tests__/predicates-test.ts index eb620abd614..4e0a4c028c0 100644 --- a/src/language/__tests__/predicates-test.js +++ b/src/language/__tests__/predicates-test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import type { ASTNode } from '../ast'; +import { ASTNode } from '../ast'; import { Kind } from '../kinds'; import { isDefinitionNode, @@ -16,10 +16,10 @@ import { } from '../predicates'; const allASTNodes: Array = Object.values(Kind).map( - (kind) => ({ kind }: any), + (kind) => ({ kind } as any), ); -function filterNodes(predicate: (ASTNode) => boolean): Array { +function filterNodes(predicate: (arg0: ASTNode) => boolean): Array { return allASTNodes.filter(predicate).map(({ kind }) => kind); } diff --git a/src/language/__tests__/printLocation-test.js b/src/language/__tests__/printLocation-test.ts similarity index 100% rename from src/language/__tests__/printLocation-test.js rename to src/language/__tests__/printLocation-test.ts diff --git a/src/language/__tests__/printer-test.js b/src/language/__tests__/printer-test.ts similarity index 97% rename from src/language/__tests__/printer-test.js rename to src/language/__tests__/printer-test.ts index 55adc17a782..b6d205139b9 100644 --- a/src/language/__tests__/printer-test.js +++ b/src/language/__tests__/printer-test.ts @@ -83,15 +83,13 @@ describe('Printer: Query document', () => { parse('{trip(wheelchair:false arriveBy:false){dateTime}}'), ); - expect(printed).to.equal( - dedent` + expect(printed).to.equal(dedent` { trip(wheelchair: false, arriveBy: false) { dateTime } } - `, - ); + `); }); it('puts arguments on multiple lines if line is long (> 80 chars)', () => { @@ -101,8 +99,7 @@ describe('Printer: Query document', () => { ), ); - expect(printed).to.equal( - dedent` + expect(printed).to.equal(dedent` { trip( wheelchair: false @@ -113,8 +110,7 @@ describe('Printer: Query document', () => { dateTime } } - `, - ); + `); }); it('Experimental: prints fragment with variable directives', () => { diff --git a/src/language/__tests__/schema-parser-test.js b/src/language/__tests__/schema-parser-test.ts similarity index 98% rename from src/language/__tests__/schema-parser-test.js rename to src/language/__tests__/schema-parser-test.ts index 2e6ffbd7454..043693bb654 100644 --- a/src/language/__tests__/schema-parser-test.js +++ b/src/language/__tests__/schema-parser-test.ts @@ -12,7 +12,7 @@ function expectSyntaxError(text: string) { return expect(() => parse(text)).to.throw(); } -function typeNode(name: mixed, loc: mixed) { +function typeNode(name: unknown, loc: unknown) { return { kind: 'NamedType', name: nameNode(name, loc), @@ -20,7 +20,7 @@ function typeNode(name: mixed, loc: mixed) { }; } -function nameNode(name: mixed, loc: mixed) { +function nameNode(name: unknown, loc: unknown) { return { kind: 'Name', value: name, @@ -28,11 +28,16 @@ function nameNode(name: mixed, loc: mixed) { }; } -function fieldNode(name: mixed, type: mixed, loc: mixed) { +function fieldNode(name: unknown, type: unknown, loc: unknown) { return fieldNodeWithArgs(name, type, [], loc); } -function fieldNodeWithArgs(name: mixed, type: mixed, args: mixed, loc: mixed) { +function fieldNodeWithArgs( + name: unknown, + type: unknown, + args: unknown, + loc: unknown, +) { return { kind: 'FieldDefinition', description: undefined, @@ -44,7 +49,7 @@ function fieldNodeWithArgs(name: mixed, type: mixed, args: mixed, loc: mixed) { }; } -function enumValueNode(name: mixed, loc: mixed) { +function enumValueNode(name: unknown, loc: unknown) { return { kind: 'EnumValueDefinition', name: nameNode(name, loc), @@ -55,10 +60,10 @@ function enumValueNode(name: mixed, loc: mixed) { } function inputValueNode( - name: mixed, - type: mixed, - defaultValue: mixed, - loc: mixed, + name: unknown, + type: unknown, + defaultValue: unknown, + loc: unknown, ) { return { kind: 'InputValueDefinition', diff --git a/src/language/__tests__/schema-printer-test.js b/src/language/__tests__/schema-printer-test.ts similarity index 100% rename from src/language/__tests__/schema-printer-test.js rename to src/language/__tests__/schema-printer-test.ts diff --git a/src/language/__tests__/source-test.js b/src/language/__tests__/source-test.ts similarity index 94% rename from src/language/__tests__/source-test.js rename to src/language/__tests__/source-test.ts index 31a34aa16d8..5510bf1fc60 100644 --- a/src/language/__tests__/source-test.js +++ b/src/language/__tests__/source-test.ts @@ -25,7 +25,7 @@ describe('Source', () => { }); it('rejects invalid locationOffset', () => { - function createSource(locationOffset: {| line: number, column: number |}) { + function createSource(locationOffset: { line: number; column: number }) { return new Source('', '', locationOffset); } diff --git a/src/language/__tests__/toJSONDeep.js b/src/language/__tests__/toJSONDeep.ts similarity index 90% rename from src/language/__tests__/toJSONDeep.js rename to src/language/__tests__/toJSONDeep.ts index 3c3fae57f3e..9c84554ce8f 100644 --- a/src/language/__tests__/toJSONDeep.js +++ b/src/language/__tests__/toJSONDeep.ts @@ -4,7 +4,7 @@ import isObjectLike from '../../jsutils/isObjectLike'; * Deeply transforms an arbitrary value to a JSON-safe value by calling toJSON * on any nested value which defines it. */ -export default function toJSONDeep(value: mixed): mixed { +export default function toJSONDeep(value: unknown): unknown { if (!isObjectLike(value)) { return value; } diff --git a/src/language/__tests__/visitor-test.js b/src/language/__tests__/visitor-test.ts similarity index 97% rename from src/language/__tests__/visitor-test.js rename to src/language/__tests__/visitor-test.ts index 1dfce965b85..fe2f5495429 100644 --- a/src/language/__tests__/visitor-test.js +++ b/src/language/__tests__/visitor-test.ts @@ -5,7 +5,7 @@ import kitchenSinkQuery from '../../__testUtils__/kitchenSinkQuery'; import invariant from '../../jsutils/invariant'; -import type { ASTNode } from '../ast'; +import { ASTNode } from '../ast'; import { Kind } from '../kinds'; import { parse } from '../parser'; import { visit, visitInParallel, BREAK, QueryDocumentKeys } from '../visitor'; @@ -157,7 +157,12 @@ describe('Visitor', () => { }; }, leave(node) { - checkVisitorFnArgs(ast, arguments, /* isEdited */ true); + checkVisitorFnArgs( + ast, + arguments, + /* isEdited */ + true, + ); return { ...node, selectionSet, @@ -195,7 +200,12 @@ describe('Visitor', () => { }; }, leave(node) { - checkVisitorFnArgs(ast, arguments, /* isEdited */ true); + checkVisitorFnArgs( + ast, + arguments, + /* isEdited */ + true, + ); return { ...node, definitions, @@ -236,7 +246,12 @@ describe('Visitor', () => { const ast = parse('{ a, b, c { a, b, c } }', { noLocation: true }); const editedAST = visit(ast, { leave(node) { - checkVisitorFnArgs(ast, arguments, /* isEdited */ true); + checkVisitorFnArgs( + ast, + arguments, + /* isEdited */ + true, + ); if (node.kind === 'Field' && node.name.value === 'b') { return null; } @@ -279,7 +294,12 @@ describe('Visitor', () => { const ast = parse('{ a { x } }', { noLocation: true }); visit(ast, { enter(node) { - checkVisitorFnArgs(ast, arguments, /* isEdited */ true); + checkVisitorFnArgs( + ast, + arguments, + /* isEdited */ + true, + ); if (node.kind === 'Field' && node.name.value === 'a') { return { kind: 'Field', @@ -867,7 +887,7 @@ describe('Visitor', () => { describe('Support for custom AST nodes', () => { const customAST = parse('{ a }'); - (customAST: any).definitions[0].selectionSet.selections.push({ + (customAST as any).definitions[0].selectionSet.selections.push({ kind: 'CustomField', name: { kind: 'Name', @@ -916,7 +936,7 @@ describe('Visitor', () => { it('does traverse unknown node kinds with visitor keys', () => { const customQueryDocumentKeys = { ...QueryDocumentKeys }; - (customQueryDocumentKeys: any).CustomField = ['name', 'selectionSet']; + (customQueryDocumentKeys as any).CustomField = ['name', 'selectionSet']; const visited = []; const visitor = { @@ -1316,7 +1336,12 @@ describe('Visitor', () => { visited.push(['enter', node.kind, getValue(node)]); }, leave(node) { - checkVisitorFnArgs(ast, arguments, /* isEdited */ true); + checkVisitorFnArgs( + ast, + arguments, + /* isEdited */ + true, + ); visited.push(['leave', node.kind, getValue(node)]); }, }, @@ -1368,7 +1393,12 @@ describe('Visitor', () => { visitInParallel([ { leave(node) { - checkVisitorFnArgs(ast, arguments, /* isEdited */ true); + checkVisitorFnArgs( + ast, + arguments, + /* isEdited */ + true, + ); if (node.kind === 'Field' && node.name.value === 'b') { return null; } @@ -1380,7 +1410,12 @@ describe('Visitor', () => { visited.push(['enter', node.kind, getValue(node)]); }, leave(node) { - checkVisitorFnArgs(ast, arguments, /* isEdited */ true); + checkVisitorFnArgs( + ast, + arguments, + /* isEdited */ + true, + ); visited.push(['leave', node.kind, getValue(node)]); }, }, diff --git a/src/language/ast.js b/src/language/ast.js deleted file mode 100644 index 1816ed34330..00000000000 --- a/src/language/ast.js +++ /dev/null @@ -1,640 +0,0 @@ -import type { Source } from './source'; -import type { TokenKindEnum } from './tokenKind'; - -/** - * Contains a range of UTF-8 character offsets and token references that - * identify the region of the source from which the AST derived. - */ -export class Location { - /** - * The character offset at which this Node begins. - */ - +start: number; - - /** - * The character offset at which this Node ends. - */ - +end: number; - - /** - * The Token at which this Node begins. - */ - +startToken: Token; - - /** - * The Token at which this Node ends. - */ - +endToken: Token; - - /** - * The Source document the AST represents. - */ - +source: Source; - - constructor(startToken: Token, endToken: Token, source: Source) { - this.start = startToken.start; - this.end = endToken.end; - this.startToken = startToken; - this.endToken = endToken; - this.source = source; - } - - toJSON(): {| start: number, end: number |} { - return { start: this.start, end: this.end }; - } - - // @deprecated: Will be removed in v17 - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - [Symbol.for('nodejs.util.inspect.custom')](): mixed { - return this.toJSON(); - } -} - -/** - * Represents a range of characters represented by a lexical token - * within a Source. - */ -export class Token { - /** - * The kind of Token. - */ - +kind: TokenKindEnum; - - /** - * The character offset at which this Node begins. - */ - +start: number; - - /** - * The character offset at which this Node ends. - */ - +end: number; - - /** - * The 1-indexed line number on which this Token appears. - */ - +line: number; - - /** - * The 1-indexed column number at which this Token begins. - */ - +column: number; - - /** - * For non-punctuation tokens, represents the interpreted value of the token. - */ - +value: string | void; - - /** - * Tokens exist as nodes in a double-linked-list amongst all tokens - * including ignored tokens. is always the first node and - * the last. - */ - +prev: Token | null; - +next: Token | null; - - constructor( - kind: TokenKindEnum, - start: number, - end: number, - line: number, - column: number, - prev: Token | null, - value?: string, - ) { - this.kind = kind; - this.start = start; - this.end = end; - this.line = line; - this.column = column; - this.value = value; - this.prev = prev; - this.next = null; - } - - toJSON(): {| - kind: TokenKindEnum, - value: string | void, - line: number, - column: number, - |} { - return { - kind: this.kind, - value: this.value, - line: this.line, - column: this.column, - }; - } - - // @deprecated: Will be removed in v17 - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - [Symbol.for('nodejs.util.inspect.custom')](): mixed { - return this.toJSON(); - } -} - -/** - * @internal - */ -export function isNode(maybeNode: mixed): boolean %checks { - return maybeNode != null && typeof maybeNode.kind === 'string'; -} - -/** - * The list of all possible AST node types. - */ -export type ASTNode = - | NameNode - | DocumentNode - | OperationDefinitionNode - | VariableDefinitionNode - | VariableNode - | SelectionSetNode - | FieldNode - | ArgumentNode - | FragmentSpreadNode - | InlineFragmentNode - | FragmentDefinitionNode - | IntValueNode - | FloatValueNode - | StringValueNode - | BooleanValueNode - | NullValueNode - | EnumValueNode - | ListValueNode - | ObjectValueNode - | ObjectFieldNode - | DirectiveNode - | NamedTypeNode - | ListTypeNode - | NonNullTypeNode - | SchemaDefinitionNode - | OperationTypeDefinitionNode - | ScalarTypeDefinitionNode - | ObjectTypeDefinitionNode - | FieldDefinitionNode - | InputValueDefinitionNode - | InterfaceTypeDefinitionNode - | UnionTypeDefinitionNode - | EnumTypeDefinitionNode - | EnumValueDefinitionNode - | InputObjectTypeDefinitionNode - | DirectiveDefinitionNode - | SchemaExtensionNode - | ScalarTypeExtensionNode - | ObjectTypeExtensionNode - | InterfaceTypeExtensionNode - | UnionTypeExtensionNode - | EnumTypeExtensionNode - | InputObjectTypeExtensionNode; - -/** - * Utility type listing all nodes indexed by their kind. - */ -export type ASTKindToNode = {| - Name: NameNode, - Document: DocumentNode, - OperationDefinition: OperationDefinitionNode, - VariableDefinition: VariableDefinitionNode, - Variable: VariableNode, - SelectionSet: SelectionSetNode, - Field: FieldNode, - Argument: ArgumentNode, - FragmentSpread: FragmentSpreadNode, - InlineFragment: InlineFragmentNode, - FragmentDefinition: FragmentDefinitionNode, - IntValue: IntValueNode, - FloatValue: FloatValueNode, - StringValue: StringValueNode, - BooleanValue: BooleanValueNode, - NullValue: NullValueNode, - EnumValue: EnumValueNode, - ListValue: ListValueNode, - ObjectValue: ObjectValueNode, - ObjectField: ObjectFieldNode, - Directive: DirectiveNode, - NamedType: NamedTypeNode, - ListType: ListTypeNode, - NonNullType: NonNullTypeNode, - SchemaDefinition: SchemaDefinitionNode, - OperationTypeDefinition: OperationTypeDefinitionNode, - ScalarTypeDefinition: ScalarTypeDefinitionNode, - ObjectTypeDefinition: ObjectTypeDefinitionNode, - FieldDefinition: FieldDefinitionNode, - InputValueDefinition: InputValueDefinitionNode, - InterfaceTypeDefinition: InterfaceTypeDefinitionNode, - UnionTypeDefinition: UnionTypeDefinitionNode, - EnumTypeDefinition: EnumTypeDefinitionNode, - EnumValueDefinition: EnumValueDefinitionNode, - InputObjectTypeDefinition: InputObjectTypeDefinitionNode, - DirectiveDefinition: DirectiveDefinitionNode, - SchemaExtension: SchemaExtensionNode, - ScalarTypeExtension: ScalarTypeExtensionNode, - ObjectTypeExtension: ObjectTypeExtensionNode, - InterfaceTypeExtension: InterfaceTypeExtensionNode, - UnionTypeExtension: UnionTypeExtensionNode, - EnumTypeExtension: EnumTypeExtensionNode, - InputObjectTypeExtension: InputObjectTypeExtensionNode, -|}; - -// Name - -export type NameNode = {| - +kind: 'Name', - +loc?: Location, - +value: string, -|}; - -// Document - -export type DocumentNode = {| - +kind: 'Document', - +loc?: Location, - +definitions: $ReadOnlyArray, -|}; - -export type DefinitionNode = - | ExecutableDefinitionNode - | TypeSystemDefinitionNode - | TypeSystemExtensionNode; - -export type ExecutableDefinitionNode = - | OperationDefinitionNode - | FragmentDefinitionNode; - -export type OperationDefinitionNode = {| - +kind: 'OperationDefinition', - +loc?: Location, - +operation: OperationTypeNode, - +name?: NameNode, - +variableDefinitions?: $ReadOnlyArray, - +directives?: $ReadOnlyArray, - +selectionSet: SelectionSetNode, -|}; - -export type OperationTypeNode = 'query' | 'mutation' | 'subscription'; - -export type VariableDefinitionNode = {| - +kind: 'VariableDefinition', - +loc?: Location, - +variable: VariableNode, - +type: TypeNode, - +defaultValue?: ValueNode, - +directives?: $ReadOnlyArray, -|}; - -export type VariableNode = {| - +kind: 'Variable', - +loc?: Location, - +name: NameNode, -|}; - -export type SelectionSetNode = {| - kind: 'SelectionSet', - loc?: Location, - selections: $ReadOnlyArray, -|}; - -export type SelectionNode = FieldNode | FragmentSpreadNode | InlineFragmentNode; - -export type FieldNode = {| - +kind: 'Field', - +loc?: Location, - +alias?: NameNode, - +name: NameNode, - +arguments?: $ReadOnlyArray, - +directives?: $ReadOnlyArray, - +selectionSet?: SelectionSetNode, -|}; - -export type ArgumentNode = {| - +kind: 'Argument', - +loc?: Location, - +name: NameNode, - +value: ValueNode, -|}; - -// Fragments - -export type FragmentSpreadNode = {| - +kind: 'FragmentSpread', - +loc?: Location, - +name: NameNode, - +directives?: $ReadOnlyArray, -|}; - -export type InlineFragmentNode = {| - +kind: 'InlineFragment', - +loc?: Location, - +typeCondition?: NamedTypeNode, - +directives?: $ReadOnlyArray, - +selectionSet: SelectionSetNode, -|}; - -export type FragmentDefinitionNode = {| - +kind: 'FragmentDefinition', - +loc?: Location, - +name: NameNode, - // Note: fragment variable definitions are experimental and may be changed - // or removed in the future. - +variableDefinitions?: $ReadOnlyArray, - +typeCondition: NamedTypeNode, - +directives?: $ReadOnlyArray, - +selectionSet: SelectionSetNode, -|}; - -// Values - -export type ValueNode = - | VariableNode - | IntValueNode - | FloatValueNode - | StringValueNode - | BooleanValueNode - | NullValueNode - | EnumValueNode - | ListValueNode - | ObjectValueNode; - -export type IntValueNode = {| - +kind: 'IntValue', - +loc?: Location, - +value: string, -|}; - -export type FloatValueNode = {| - +kind: 'FloatValue', - +loc?: Location, - +value: string, -|}; - -export type StringValueNode = {| - +kind: 'StringValue', - +loc?: Location, - +value: string, - +block?: boolean, -|}; - -export type BooleanValueNode = {| - +kind: 'BooleanValue', - +loc?: Location, - +value: boolean, -|}; - -export type NullValueNode = {| - +kind: 'NullValue', - +loc?: Location, -|}; - -export type EnumValueNode = {| - +kind: 'EnumValue', - +loc?: Location, - +value: string, -|}; - -export type ListValueNode = {| - +kind: 'ListValue', - +loc?: Location, - +values: $ReadOnlyArray, -|}; - -export type ObjectValueNode = {| - +kind: 'ObjectValue', - +loc?: Location, - +fields: $ReadOnlyArray, -|}; - -export type ObjectFieldNode = {| - +kind: 'ObjectField', - +loc?: Location, - +name: NameNode, - +value: ValueNode, -|}; - -// Directives - -export type DirectiveNode = {| - +kind: 'Directive', - +loc?: Location, - +name: NameNode, - +arguments?: $ReadOnlyArray, -|}; - -// Type Reference - -export type TypeNode = NamedTypeNode | ListTypeNode | NonNullTypeNode; - -export type NamedTypeNode = {| - +kind: 'NamedType', - +loc?: Location, - +name: NameNode, -|}; - -export type ListTypeNode = {| - +kind: 'ListType', - +loc?: Location, - +type: TypeNode, -|}; - -export type NonNullTypeNode = {| - +kind: 'NonNullType', - +loc?: Location, - +type: NamedTypeNode | ListTypeNode, -|}; - -// Type System Definition - -export type TypeSystemDefinitionNode = - | SchemaDefinitionNode - | TypeDefinitionNode - | DirectiveDefinitionNode; - -export type SchemaDefinitionNode = {| - +kind: 'SchemaDefinition', - +loc?: Location, - +description?: StringValueNode, - +directives?: $ReadOnlyArray, - +operationTypes: $ReadOnlyArray, -|}; - -export type OperationTypeDefinitionNode = {| - +kind: 'OperationTypeDefinition', - +loc?: Location, - +operation: OperationTypeNode, - +type: NamedTypeNode, -|}; - -// Type Definition - -export type TypeDefinitionNode = - | ScalarTypeDefinitionNode - | ObjectTypeDefinitionNode - | InterfaceTypeDefinitionNode - | UnionTypeDefinitionNode - | EnumTypeDefinitionNode - | InputObjectTypeDefinitionNode; - -export type ScalarTypeDefinitionNode = {| - +kind: 'ScalarTypeDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +directives?: $ReadOnlyArray, -|}; - -export type ObjectTypeDefinitionNode = {| - +kind: 'ObjectTypeDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +interfaces?: $ReadOnlyArray, - +directives?: $ReadOnlyArray, - +fields?: $ReadOnlyArray, -|}; - -export type FieldDefinitionNode = {| - +kind: 'FieldDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +arguments?: $ReadOnlyArray, - +type: TypeNode, - +directives?: $ReadOnlyArray, -|}; - -export type InputValueDefinitionNode = {| - +kind: 'InputValueDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +type: TypeNode, - +defaultValue?: ValueNode, - +directives?: $ReadOnlyArray, -|}; - -export type InterfaceTypeDefinitionNode = {| - +kind: 'InterfaceTypeDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +interfaces?: $ReadOnlyArray, - +directives?: $ReadOnlyArray, - +fields?: $ReadOnlyArray, -|}; - -export type UnionTypeDefinitionNode = {| - +kind: 'UnionTypeDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +directives?: $ReadOnlyArray, - +types?: $ReadOnlyArray, -|}; - -export type EnumTypeDefinitionNode = {| - +kind: 'EnumTypeDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +directives?: $ReadOnlyArray, - +values?: $ReadOnlyArray, -|}; - -export type EnumValueDefinitionNode = {| - +kind: 'EnumValueDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +directives?: $ReadOnlyArray, -|}; - -export type InputObjectTypeDefinitionNode = {| - +kind: 'InputObjectTypeDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +directives?: $ReadOnlyArray, - +fields?: $ReadOnlyArray, -|}; - -// Directive Definitions - -export type DirectiveDefinitionNode = {| - +kind: 'DirectiveDefinition', - +loc?: Location, - +description?: StringValueNode, - +name: NameNode, - +arguments?: $ReadOnlyArray, - +repeatable: boolean, - +locations: $ReadOnlyArray, -|}; - -// Type System Extensions - -export type TypeSystemExtensionNode = SchemaExtensionNode | TypeExtensionNode; - -export type SchemaExtensionNode = {| - +kind: 'SchemaExtension', - +loc?: Location, - +directives?: $ReadOnlyArray, - +operationTypes?: $ReadOnlyArray, -|}; - -// Type Extensions - -export type TypeExtensionNode = - | ScalarTypeExtensionNode - | ObjectTypeExtensionNode - | InterfaceTypeExtensionNode - | UnionTypeExtensionNode - | EnumTypeExtensionNode - | InputObjectTypeExtensionNode; - -export type ScalarTypeExtensionNode = {| - +kind: 'ScalarTypeExtension', - +loc?: Location, - +name: NameNode, - +directives?: $ReadOnlyArray, -|}; - -export type ObjectTypeExtensionNode = {| - +kind: 'ObjectTypeExtension', - +loc?: Location, - +name: NameNode, - +interfaces?: $ReadOnlyArray, - +directives?: $ReadOnlyArray, - +fields?: $ReadOnlyArray, -|}; - -export type InterfaceTypeExtensionNode = {| - +kind: 'InterfaceTypeExtension', - +loc?: Location, - +name: NameNode, - +interfaces?: $ReadOnlyArray, - +directives?: $ReadOnlyArray, - +fields?: $ReadOnlyArray, -|}; - -export type UnionTypeExtensionNode = {| - +kind: 'UnionTypeExtension', - +loc?: Location, - +name: NameNode, - +directives?: $ReadOnlyArray, - +types?: $ReadOnlyArray, -|}; - -export type EnumTypeExtensionNode = {| - +kind: 'EnumTypeExtension', - +loc?: Location, - +name: NameNode, - +directives?: $ReadOnlyArray, - +values?: $ReadOnlyArray, -|}; - -export type InputObjectTypeExtensionNode = {| - +kind: 'InputObjectTypeExtension', - +loc?: Location, - +name: NameNode, - +directives?: $ReadOnlyArray, - +fields?: $ReadOnlyArray, -|}; diff --git a/src/language/ast.ts b/src/language/ast.ts new file mode 100644 index 00000000000..162abd8f305 --- /dev/null +++ b/src/language/ast.ts @@ -0,0 +1,560 @@ +import { Source } from "./source"; +import { TokenKindEnum } from "./tokenKind"; + +/** + * Contains a range of UTF-8 character offsets and token references that + * identify the region of the source from which the AST derived. + */ +export class Location { + /** + * The character offset at which this Node begins. + */ + +start: number; + + /** + * The character offset at which this Node ends. + */ + +end: number; + + /** + * The Token at which this Node begins. + */ + +startToken: Token; + + /** + * The Token at which this Node ends. + */ + +endToken: Token; + + /** + * The Source document the AST represents. + */ + +source: Source; + + constructor(startToken: Token, endToken: Token, source: Source) { + this.start = startToken.start; + this.end = endToken.end; + this.startToken = startToken; + this.endToken = endToken; + this.source = source; + } + + toJSON(): {start: number;end: number;} { + return { start: this.start, end: this.end }; + } + + // @deprecated: Will be removed in v17 + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet + [Symbol.for('nodejs.util.inspect.custom')](): unknown { + return this.toJSON(); + } +} + +/** + * Represents a range of characters represented by a lexical token + * within a Source. + */ +export class Token { + /** + * The kind of Token. + */ + +kind: TokenKindEnum; + + /** + * The character offset at which this Node begins. + */ + +start: number; + + /** + * The character offset at which this Node ends. + */ + +end: number; + + /** + * The 1-indexed line number on which this Token appears. + */ + +line: number; + + /** + * The 1-indexed column number at which this Token begins. + */ + +column: number; + + /** + * For non-punctuation tokens, represents the interpreted value of the token. + */ + +value: string | void; + + /** + * Tokens exist as nodes in a double-linked-list amongst all tokens + * including ignored tokens. is always the first node and + * the last. + */ + +prev: Token | null; + +next: Token | null; + + constructor(kind: TokenKindEnum, start: number, end: number, line: number, column: number, prev: Token | null, value?: string) { + this.kind = kind; + this.start = start; + this.end = end; + this.line = line; + this.column = column; + this.value = value; + this.prev = prev; + this.next = null; + } + + toJSON(): { + kind: TokenKindEnum; + value: string | void; + line: number; + column: number; + } { + return { + kind: this.kind, + value: this.value, + line: this.line, + column: this.column + }; + } + + // @deprecated: Will be removed in v17 + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet + [Symbol.for('nodejs.util.inspect.custom')](): unknown { + return this.toJSON(); + } +} + +/** + * @internal + */ +export function isNode(maybeNode: unknown): boolean { + return maybeNode != null && typeof maybeNode.kind === 'string'; +} + +/** + * The list of all possible AST node types. + */ +export type ASTNode = NameNode | DocumentNode | OperationDefinitionNode | VariableDefinitionNode | VariableNode | SelectionSetNode | FieldNode | ArgumentNode | FragmentSpreadNode | InlineFragmentNode | FragmentDefinitionNode | IntValueNode | FloatValueNode | StringValueNode | BooleanValueNode | NullValueNode | EnumValueNode | ListValueNode | ObjectValueNode | ObjectFieldNode | DirectiveNode | NamedTypeNode | ListTypeNode | NonNullTypeNode | SchemaDefinitionNode | OperationTypeDefinitionNode | ScalarTypeDefinitionNode | ObjectTypeDefinitionNode | FieldDefinitionNode | InputValueDefinitionNode | InterfaceTypeDefinitionNode | UnionTypeDefinitionNode | EnumTypeDefinitionNode | EnumValueDefinitionNode | InputObjectTypeDefinitionNode | DirectiveDefinitionNode | SchemaExtensionNode | ScalarTypeExtensionNode | ObjectTypeExtensionNode | InterfaceTypeExtensionNode | UnionTypeExtensionNode | EnumTypeExtensionNode | InputObjectTypeExtensionNode; + +/** + * Utility type listing all nodes indexed by their kind. + */ +export type ASTKindToNode = { + Name: NameNode; + Document: DocumentNode; + OperationDefinition: OperationDefinitionNode; + VariableDefinition: VariableDefinitionNode; + Variable: VariableNode; + SelectionSet: SelectionSetNode; + Field: FieldNode; + Argument: ArgumentNode; + FragmentSpread: FragmentSpreadNode; + InlineFragment: InlineFragmentNode; + FragmentDefinition: FragmentDefinitionNode; + IntValue: IntValueNode; + FloatValue: FloatValueNode; + StringValue: StringValueNode; + BooleanValue: BooleanValueNode; + NullValue: NullValueNode; + EnumValue: EnumValueNode; + ListValue: ListValueNode; + ObjectValue: ObjectValueNode; + ObjectField: ObjectFieldNode; + Directive: DirectiveNode; + NamedType: NamedTypeNode; + ListType: ListTypeNode; + NonNullType: NonNullTypeNode; + SchemaDefinition: SchemaDefinitionNode; + OperationTypeDefinition: OperationTypeDefinitionNode; + ScalarTypeDefinition: ScalarTypeDefinitionNode; + ObjectTypeDefinition: ObjectTypeDefinitionNode; + FieldDefinition: FieldDefinitionNode; + InputValueDefinition: InputValueDefinitionNode; + InterfaceTypeDefinition: InterfaceTypeDefinitionNode; + UnionTypeDefinition: UnionTypeDefinitionNode; + EnumTypeDefinition: EnumTypeDefinitionNode; + EnumValueDefinition: EnumValueDefinitionNode; + InputObjectTypeDefinition: InputObjectTypeDefinitionNode; + DirectiveDefinition: DirectiveDefinitionNode; + SchemaExtension: SchemaExtensionNode; + ScalarTypeExtension: ScalarTypeExtensionNode; + ObjectTypeExtension: ObjectTypeExtensionNode; + InterfaceTypeExtension: InterfaceTypeExtensionNode; + UnionTypeExtension: UnionTypeExtensionNode; + EnumTypeExtension: EnumTypeExtensionNode; + InputObjectTypeExtension: InputObjectTypeExtensionNode; +}; + +// Name + +export type NameNode = { + readonly kind: "Name"; + readonly loc?: Location; + readonly value: string; +}; + +// Document + +export type DocumentNode = { + readonly kind: "Document"; + readonly loc?: Location; + readonly definitions: ReadonlyArray; +}; + +export type DefinitionNode = ExecutableDefinitionNode | TypeSystemDefinitionNode | TypeSystemExtensionNode; + +export type ExecutableDefinitionNode = OperationDefinitionNode | FragmentDefinitionNode; + +export type OperationDefinitionNode = { + readonly kind: "OperationDefinition"; + readonly loc?: Location; + readonly operation: OperationTypeNode; + readonly name?: NameNode; + readonly variableDefinitions?: ReadonlyArray; + readonly directives?: ReadonlyArray; + readonly selectionSet: SelectionSetNode; +}; + +export type OperationTypeNode = "query" | "mutation" | "subscription"; + +export type VariableDefinitionNode = { + readonly kind: "VariableDefinition"; + readonly loc?: Location; + readonly variable: VariableNode; + readonly type: TypeNode; + readonly defaultValue?: ValueNode; + readonly directives?: ReadonlyArray; +}; + +export type VariableNode = { + readonly kind: "Variable"; + readonly loc?: Location; + readonly name: NameNode; +}; + +export type SelectionSetNode = { + kind: "SelectionSet"; + loc?: Location; + selections: ReadonlyArray; +}; + +export type SelectionNode = FieldNode | FragmentSpreadNode | InlineFragmentNode; + +export type FieldNode = { + readonly kind: "Field"; + readonly loc?: Location; + readonly alias?: NameNode; + readonly name: NameNode; + readonly arguments?: ReadonlyArray; + readonly directives?: ReadonlyArray; + readonly selectionSet?: SelectionSetNode; +}; + +export type ArgumentNode = { + readonly kind: "Argument"; + readonly loc?: Location; + readonly name: NameNode; + readonly value: ValueNode; +}; + +// Fragments + +export type FragmentSpreadNode = { + readonly kind: "FragmentSpread"; + readonly loc?: Location; + readonly name: NameNode; + readonly directives?: ReadonlyArray; +}; + +export type InlineFragmentNode = { + readonly kind: "InlineFragment"; + readonly loc?: Location; + readonly typeCondition?: NamedTypeNode; + readonly directives?: ReadonlyArray; + readonly selectionSet: SelectionSetNode; +}; + +export type FragmentDefinitionNode = { + readonly kind: "FragmentDefinition"; + readonly loc?: Location; + readonly name: NameNode; + // Note: fragment variable definitions are experimental and may be changed + // or removed in the future. + readonly variableDefinitions?: ReadonlyArray; + readonly typeCondition: NamedTypeNode; + readonly directives?: ReadonlyArray; + readonly selectionSet: SelectionSetNode; +}; + +// Values + +export type ValueNode = VariableNode | IntValueNode | FloatValueNode | StringValueNode | BooleanValueNode | NullValueNode | EnumValueNode | ListValueNode | ObjectValueNode; + +export type IntValueNode = { + readonly kind: "IntValue"; + readonly loc?: Location; + readonly value: string; +}; + +export type FloatValueNode = { + readonly kind: "FloatValue"; + readonly loc?: Location; + readonly value: string; +}; + +export type StringValueNode = { + readonly kind: "StringValue"; + readonly loc?: Location; + readonly value: string; + readonly block?: boolean; +}; + +export type BooleanValueNode = { + readonly kind: "BooleanValue"; + readonly loc?: Location; + readonly value: boolean; +}; + +export type NullValueNode = { + readonly kind: "NullValue"; + readonly loc?: Location; +}; + +export type EnumValueNode = { + readonly kind: "EnumValue"; + readonly loc?: Location; + readonly value: string; +}; + +export type ListValueNode = { + readonly kind: "ListValue"; + readonly loc?: Location; + readonly values: ReadonlyArray; +}; + +export type ObjectValueNode = { + readonly kind: "ObjectValue"; + readonly loc?: Location; + readonly fields: ReadonlyArray; +}; + +export type ObjectFieldNode = { + readonly kind: "ObjectField"; + readonly loc?: Location; + readonly name: NameNode; + readonly value: ValueNode; +}; + +// Directives + +export type DirectiveNode = { + readonly kind: "Directive"; + readonly loc?: Location; + readonly name: NameNode; + readonly arguments?: ReadonlyArray; +}; + +// Type Reference + +export type TypeNode = NamedTypeNode | ListTypeNode | NonNullTypeNode; + +export type NamedTypeNode = { + readonly kind: "NamedType"; + readonly loc?: Location; + readonly name: NameNode; +}; + +export type ListTypeNode = { + readonly kind: "ListType"; + readonly loc?: Location; + readonly type: TypeNode; +}; + +export type NonNullTypeNode = { + readonly kind: "NonNullType"; + readonly loc?: Location; + readonly type: NamedTypeNode | ListTypeNode; +}; + +// Type System Definition + +export type TypeSystemDefinitionNode = SchemaDefinitionNode | TypeDefinitionNode | DirectiveDefinitionNode; + +export type SchemaDefinitionNode = { + readonly kind: "SchemaDefinition"; + readonly loc?: Location; + readonly description?: StringValueNode; + readonly directives?: ReadonlyArray; + readonly operationTypes: ReadonlyArray; +}; + +export type OperationTypeDefinitionNode = { + readonly kind: "OperationTypeDefinition"; + readonly loc?: Location; + readonly operation: OperationTypeNode; + readonly type: NamedTypeNode; +}; + +// Type Definition + +export type TypeDefinitionNode = ScalarTypeDefinitionNode | ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode | UnionTypeDefinitionNode | EnumTypeDefinitionNode | InputObjectTypeDefinitionNode; + +export type ScalarTypeDefinitionNode = { + readonly kind: "ScalarTypeDefinition"; + readonly loc?: Location; + readonly description?: StringValueNode; + readonly name: NameNode; + readonly directives?: ReadonlyArray; +}; + +export type ObjectTypeDefinitionNode = { + readonly kind: "ObjectTypeDefinition"; + readonly loc?: Location; + readonly description?: StringValueNode; + readonly name: NameNode; + readonly interfaces?: ReadonlyArray; + readonly directives?: ReadonlyArray; + readonly fields?: ReadonlyArray; +}; + +export type FieldDefinitionNode = { + readonly kind: "FieldDefinition"; + readonly loc?: Location; + readonly description?: StringValueNode; + readonly name: NameNode; + readonly arguments?: ReadonlyArray; + readonly type: TypeNode; + readonly directives?: ReadonlyArray; +}; + +export type InputValueDefinitionNode = { + readonly kind: "InputValueDefinition"; + readonly loc?: Location; + readonly description?: StringValueNode; + readonly name: NameNode; + readonly type: TypeNode; + readonly defaultValue?: ValueNode; + readonly directives?: ReadonlyArray; +}; + +export type InterfaceTypeDefinitionNode = { + readonly kind: "InterfaceTypeDefinition"; + readonly loc?: Location; + readonly description?: StringValueNode; + readonly name: NameNode; + readonly interfaces?: ReadonlyArray; + readonly directives?: ReadonlyArray; + readonly fields?: ReadonlyArray; +}; + +export type UnionTypeDefinitionNode = { + readonly kind: "UnionTypeDefinition"; + readonly loc?: Location; + readonly description?: StringValueNode; + readonly name: NameNode; + readonly directives?: ReadonlyArray; + readonly types?: ReadonlyArray; +}; + +export type EnumTypeDefinitionNode = { + readonly kind: "EnumTypeDefinition"; + readonly loc?: Location; + readonly description?: StringValueNode; + readonly name: NameNode; + readonly directives?: ReadonlyArray; + readonly values?: ReadonlyArray; +}; + +export type EnumValueDefinitionNode = { + readonly kind: "EnumValueDefinition"; + readonly loc?: Location; + readonly description?: StringValueNode; + readonly name: NameNode; + readonly directives?: ReadonlyArray; +}; + +export type InputObjectTypeDefinitionNode = { + readonly kind: "InputObjectTypeDefinition"; + readonly loc?: Location; + readonly description?: StringValueNode; + readonly name: NameNode; + readonly directives?: ReadonlyArray; + readonly fields?: ReadonlyArray; +}; + +// Directive Definitions + +export type DirectiveDefinitionNode = { + readonly kind: "DirectiveDefinition"; + readonly loc?: Location; + readonly description?: StringValueNode; + readonly name: NameNode; + readonly arguments?: ReadonlyArray; + readonly repeatable: boolean; + readonly locations: ReadonlyArray; +}; + +// Type System Extensions + +export type TypeSystemExtensionNode = SchemaExtensionNode | TypeExtensionNode; + +export type SchemaExtensionNode = { + readonly kind: "SchemaExtension"; + readonly loc?: Location; + readonly directives?: ReadonlyArray; + readonly operationTypes?: ReadonlyArray; +}; + +// Type Extensions + +export type TypeExtensionNode = ScalarTypeExtensionNode | ObjectTypeExtensionNode | InterfaceTypeExtensionNode | UnionTypeExtensionNode | EnumTypeExtensionNode | InputObjectTypeExtensionNode; + +export type ScalarTypeExtensionNode = { + readonly kind: "ScalarTypeExtension"; + readonly loc?: Location; + readonly name: NameNode; + readonly directives?: ReadonlyArray; +}; + +export type ObjectTypeExtensionNode = { + readonly kind: "ObjectTypeExtension"; + readonly loc?: Location; + readonly name: NameNode; + readonly interfaces?: ReadonlyArray; + readonly directives?: ReadonlyArray; + readonly fields?: ReadonlyArray; +}; + +export type InterfaceTypeExtensionNode = { + readonly kind: "InterfaceTypeExtension"; + readonly loc?: Location; + readonly name: NameNode; + readonly interfaces?: ReadonlyArray; + readonly directives?: ReadonlyArray; + readonly fields?: ReadonlyArray; +}; + +export type UnionTypeExtensionNode = { + readonly kind: "UnionTypeExtension"; + readonly loc?: Location; + readonly name: NameNode; + readonly directives?: ReadonlyArray; + readonly types?: ReadonlyArray; +}; + +export type EnumTypeExtensionNode = { + readonly kind: "EnumTypeExtension"; + readonly loc?: Location; + readonly name: NameNode; + readonly directives?: ReadonlyArray; + readonly values?: ReadonlyArray; +}; + +export type InputObjectTypeExtensionNode = { + readonly kind: "InputObjectTypeExtension"; + readonly loc?: Location; + readonly name: NameNode; + readonly directives?: ReadonlyArray; + readonly fields?: ReadonlyArray; +}; \ No newline at end of file diff --git a/src/language/blockString.js b/src/language/blockString.ts similarity index 94% rename from src/language/blockString.js rename to src/language/blockString.ts index 65b70ba696a..fbdb2124a9d 100644 --- a/src/language/blockString.js +++ b/src/language/blockString.ts @@ -55,18 +55,22 @@ export function getBlockStringIndentation(value: string): number { for (let i = 0; i < value.length; ++i) { switch (value.charCodeAt(i)) { - case 13: // \r + case 13: + // \r if (value.charCodeAt(i + 1) === 10) { ++i; // skip \r\n as one symbol } + // falls through - case 10: // \n + case 10: + // \n isFirstLine = false; isEmptyLine = true; indent = 0; break; - case 9: // \t - case 32: // + case 9: + case 32: + // ++indent; break; default: @@ -77,6 +81,7 @@ export function getBlockStringIndentation(value: string): number { ) { commonIndent = indent; } + isEmptyLine = false; } } @@ -93,8 +98,8 @@ export function getBlockStringIndentation(value: string): number { */ export function printBlockString( value: string, - indentation?: string = '', - preferMultipleLines?: boolean = false, + indentation: string = '', + preferMultipleLines: boolean = false, ): string { const isSingleLine = value.indexOf('\n') === -1; const hasLeadingSpace = value[0] === ' ' || value[0] === '\t'; diff --git a/src/language/directiveLocation.js b/src/language/directiveLocation.ts similarity index 95% rename from src/language/directiveLocation.js rename to src/language/directiveLocation.ts index 9fa1348cf8a..943fffd84d1 100644 --- a/src/language/directiveLocation.js +++ b/src/language/directiveLocation.ts @@ -1,3 +1,5 @@ +import { $Values } from 'utility-types'; + /** * The set of allowed directive location values. */ diff --git a/src/language/experimentalOnlineParser/grammar.js b/src/language/experimentalOnlineParser/grammar.ts similarity index 98% rename from src/language/experimentalOnlineParser/grammar.js rename to src/language/experimentalOnlineParser/grammar.ts index 0ab77885340..6d44dc7487a 100644 --- a/src/language/experimentalOnlineParser/grammar.js +++ b/src/language/experimentalOnlineParser/grammar.ts @@ -1,6 +1,6 @@ -export type GraphQLGrammarType = {| - [name: string]: GraphQLGrammarRule, -|}; +export type GraphQLGrammarType = { + [name: string]: GraphQLGrammarRule; +}; export type GraphQLGrammarRuleName = string; export type GraphQLGrammarRuleConstraint = | GraphQLGrammarTokenConstraint @@ -8,7 +8,7 @@ export type GraphQLGrammarRuleConstraint = | GraphQLGrammarListOfTypeConstraint | GraphQLGrammarPeekConstraint; export type GraphQLGrammarConstraintsSet = Array< - GraphQLGrammarRuleName | GraphQLGrammarRuleConstraint, + GraphQLGrammarRuleName | GraphQLGrammarRuleConstraint >; export type GraphQLGrammarRule = | GraphQLGrammarRuleName @@ -16,8 +16,8 @@ export type GraphQLGrammarRule = | GraphQLGrammarConstraintsSet; export interface GraphQLGrammarBaseRuleConstraint { butNot?: - | ?GraphQLGrammarTokenConstraint - | ?Array; + | (GraphQLGrammarTokenConstraint | null | undefined) + | (Array | null | undefined); optional?: boolean; eatNextOnFail?: boolean; } @@ -44,8 +44,8 @@ export interface GraphQLGrammarTokenConstraint | 'String' | 'BlockString' | 'Comment'; - ofValue?: ?string; - oneOf?: ?Array; + ofValue?: string | null | undefined; + oneOf?: Array | null | undefined; tokenName?: string; definitionName?: boolean; typeName?: boolean; @@ -69,7 +69,7 @@ export interface GraphQLGrammarPeekConstraintCondition { end?: boolean; } -const grammar: GraphQLGrammarType = ({ +const grammar: GraphQLGrammarType = { Name: { token: 'Name' }, String: { token: 'String' }, BlockString: { token: 'BlockString' }, @@ -994,6 +994,6 @@ const grammar: GraphQLGrammarType = ({ tokenName: 'EnumValue', }, // FIXME: enforce proper typing -}: any); +} as any; export default grammar; diff --git a/src/language/experimentalOnlineParser/index.js b/src/language/experimentalOnlineParser/index.ts similarity index 100% rename from src/language/experimentalOnlineParser/index.js rename to src/language/experimentalOnlineParser/index.ts diff --git a/src/language/experimentalOnlineParser/onlineParser.js b/src/language/experimentalOnlineParser/onlineParser.ts similarity index 94% rename from src/language/experimentalOnlineParser/onlineParser.js rename to src/language/experimentalOnlineParser/onlineParser.ts index f296d1c8e24..0dabca86f46 100644 --- a/src/language/experimentalOnlineParser/onlineParser.js +++ b/src/language/experimentalOnlineParser/onlineParser.ts @@ -2,7 +2,7 @@ import { Lexer } from '../lexer'; import { Source } from '../source'; import GraphQLGrammar from './grammar'; -import type { +import { GraphQLGrammarRule, GraphQLGrammarRuleName, GraphQLGrammarRuleConstraint, @@ -73,35 +73,35 @@ type OnlineParserRule = | PeekOnlineParserRule | ConstraintsSetOnlineParserRule; -export type OnlineParserState = {| - rules: Array, - kind: () => string, - step: () => number, - levels: Array, - indentLevel: number, - name: string | null, - type: string | null, -|}; - -type Token = {| - kind: string, - value: string, - tokenName?: ?string, - ruleName?: ?string, -|}; - -type LexerToken = {| - kind: string, - value: ?string, -|}; - -type OnlineParserConfig = {| - tabSize: number, -|}; - -type OnlineParserConfigOption = {| - tabSize: ?number, -|}; +export type OnlineParserState = { + rules: Array; + kind: () => string; + step: () => number; + levels: Array; + indentLevel: number; + name: string | null; + type: string | null; +}; + +type Token = { + kind: string; + value: string; + tokenName?: string | null | undefined; + ruleName?: string | null | undefined; +}; + +type LexerToken = { + kind: string; + value: string | null | undefined; +}; + +type OnlineParserConfig = { + tabSize: number; +}; + +type OnlineParserConfigOption = { + tabSize: number | null | undefined; +}; export class OnlineParser { state: OnlineParserState; @@ -171,7 +171,7 @@ export class OnlineParser { } parseToken(): Token { - const rule = (this._getNextRule(): any); + const rule = this._getNextRule() as any; if (this.sol()) { this.state.indentLevel = Math.floor( @@ -452,7 +452,7 @@ export class OnlineParser { return this.state.rules[this.state.rules.length - 1] || null; } - _popMatchedRule(token: ?Token) { + _popMatchedRule(token: Token | null | undefined) { const rule = this.state.rules.pop(); if (!rule) { return; @@ -550,7 +550,8 @@ export class OnlineParser { switch (this._getRuleKind(rule)) { case RuleKind.RULE_NAME: - rule = (rule: GraphQLGrammarRuleName); + rule = rule as GraphQLGrammarRuleName; + this._pushRule( GraphQLGrammar[rule], depth, @@ -558,9 +559,10 @@ export class OnlineParser { step, state, ); + break; case RuleKind.CONSTRAINTS_SET: - rule = (rule: GraphQLGrammarConstraintsSet); + rule = rule as GraphQLGrammarConstraintsSet; this.state.rules.push({ name: name || '', depth, @@ -580,7 +582,7 @@ export class OnlineParser { }); break; case RuleKind.OF_TYPE_CONSTRAINT: - rule = (rule: GraphQLGrammarOfTypeConstraint); + rule = rule as GraphQLGrammarOfTypeConstraint; this.state.rules.push({ name: name || '', ofType: rule.ofType, @@ -603,7 +605,7 @@ export class OnlineParser { }); break; case RuleKind.LIST_OF_TYPE_CONSTRAINT: - rule = (rule: GraphQLGrammarListOfTypeConstraint); + rule = rule as GraphQLGrammarListOfTypeConstraint; this.state.rules.push({ listOfType: rule.listOfType, optional: Boolean(rule.optional), @@ -625,7 +627,7 @@ export class OnlineParser { }); break; case RuleKind.TOKEN_CONSTRAINT: - rule = (rule: GraphQLGrammarTokenConstraint); + rule = rule as GraphQLGrammarTokenConstraint; this.state.rules.push({ token: rule.token, ofValue: rule.ofValue, @@ -651,7 +653,7 @@ export class OnlineParser { }); break; case RuleKind.PEEK_CONSTRAINT: - rule = (rule: GraphQLGrammarPeekConstraint); + rule = rule as GraphQLGrammarPeekConstraint; this.state.rules.push({ peek: rule.peek, optional: Boolean(rule.optional), @@ -709,12 +711,12 @@ export class OnlineParser { } _advanceToken(): LexerToken { - return (this._lexer.advance(): any); + return this._lexer.advance() as any; } _lookAhead(): LexerToken { try { - return (this._lexer.lookahead(): any); + return this._lexer.lookahead() as any; } catch (err) { return { kind: TokenKind.INVALID, value: '' }; } diff --git a/src/language/index.js b/src/language/index.ts similarity index 83% rename from src/language/index.js rename to src/language/index.ts index 6055ff4fe30..81dd086b306 100644 --- a/src/language/index.js +++ b/src/language/index.ts @@ -1,31 +1,30 @@ export { Source } from './source'; export { getLocation } from './location'; -export type { SourceLocation } from './location'; +export { SourceLocation } from './location'; export { printLocation, printSourceLocation } from './printLocation'; export { Kind } from './kinds'; -export type { KindEnum } from './kinds'; +export { KindEnum } from './kinds'; export { TokenKind } from './tokenKind'; -export type { TokenKindEnum } from './tokenKind'; +export { TokenKindEnum } from './tokenKind'; export { Lexer } from './lexer'; export { parse, parseValue, parseType } from './parser'; -export type { ParseOptions } from './parser'; +export { ParseOptions } from './parser'; export { print } from './printer'; export { visit, visitInParallel, getVisitFn, BREAK } from './visitor'; -export type { ASTVisitor, Visitor, VisitFn, VisitorKeyMap } from './visitor'; +export { ASTVisitor, Visitor, VisitFn, VisitorKeyMap } from './visitor'; export { Location, Token } from './ast'; -export type { +export { ASTNode, - ASTKindToNode, - // Each kind of AST node + ASTKindToNode, // Each kind of AST node NameNode, DocumentNode, DefinitionNode, @@ -94,4 +93,4 @@ export { } from './predicates'; export { DirectiveLocation } from './directiveLocation'; -export type { DirectiveLocationEnum } from './directiveLocation'; +export { DirectiveLocationEnum } from './directiveLocation'; diff --git a/src/language/kinds.js b/src/language/kinds.ts similarity index 97% rename from src/language/kinds.js rename to src/language/kinds.ts index 99e3e4a9ead..56c9bd9a8a1 100644 --- a/src/language/kinds.js +++ b/src/language/kinds.ts @@ -1,3 +1,5 @@ +import { $Values } from 'utility-types'; + /** * The set of allowed kind values for AST nodes. */ diff --git a/src/language/lexer.js b/src/language/lexer.ts similarity index 86% rename from src/language/lexer.js rename to src/language/lexer.ts index ad42ce98976..4178752452c 100644 --- a/src/language/lexer.js +++ b/src/language/lexer.ts @@ -1,7 +1,7 @@ import { syntaxError } from '../error/syntaxError'; -import type { Source } from './source'; -import type { TokenKindEnum } from './tokenKind'; +import { Source } from './source'; +import { TokenKindEnum } from './tokenKind'; import { Token } from './ast'; import { TokenKind } from './tokenKind'; import { dedentBlockStringValue } from './blockString'; @@ -65,7 +65,7 @@ export class Lexer { if (token.kind !== TokenKind.EOF) { do { // Note: next is only mutable during parsing, so we cast to allow this. - token = token.next ?? ((token: any).next = readToken(this, token)); + token = token.next ?? ((token as any).next = readToken(this, token)); } while (token.kind === TokenKind.COMMENT); } return token; @@ -75,7 +75,7 @@ export class Lexer { /** * @internal */ -export function isPunctuatorTokenKind(kind: TokenKindEnum): boolean %checks { +export function isPunctuatorTokenKind(kind: TokenKindEnum): boolean { return ( kind === TokenKind.BANG || kind === TokenKind.DOLLAR || @@ -98,12 +98,10 @@ function printCharCode(code: number): string { return ( // NaN/undefined represents access beyond the end of the file. isNaN(code) - ? TokenKind.EOF - : // Trust JSON for ASCII. - code < 0x007f - ? JSON.stringify(String.fromCharCode(code)) - : // Otherwise print the escaped form. - `"\\u${('00' + code.toString(16).toUpperCase()).slice(-4)}"` + ? TokenKind.EOF // Trust JSON for ASCII. + : code < 0x007f + ? JSON.stringify(String.fromCharCode(code)) // Otherwise print the escaped form. + : `"\\u${('00' + code.toString(16).toUpperCase()).slice(-4)}"` ); } @@ -128,135 +126,159 @@ function readToken(lexer: Lexer, prev: Token): Token { // SourceCharacter switch (code) { - case 0xfeff: // - case 9: // \t - case 32: // - case 44: // , + case 0xfeff: + case 9: + case 32: + case 44: + // , ++pos; continue; - case 10: // \n + case 10: + // \n ++pos; ++lexer.line; lexer.lineStart = pos; continue; - case 13: // \r + case 13: + // \r if (body.charCodeAt(pos + 1) === 10) { pos += 2; } else { ++pos; } + ++lexer.line; lexer.lineStart = pos; continue; - case 33: // ! + case 33: + // ! return new Token(TokenKind.BANG, pos, pos + 1, line, col, prev); - case 35: // # + case 35: + // # return readComment(source, pos, line, col, prev); - case 36: // $ + case 36: + // $ return new Token(TokenKind.DOLLAR, pos, pos + 1, line, col, prev); - case 38: // & + case 38: + // & return new Token(TokenKind.AMP, pos, pos + 1, line, col, prev); - case 40: // ( + case 40: + // ( return new Token(TokenKind.PAREN_L, pos, pos + 1, line, col, prev); - case 41: // ) + case 41: + // ) return new Token(TokenKind.PAREN_R, pos, pos + 1, line, col, prev); - case 46: // . + case 46: + // . if ( body.charCodeAt(pos + 1) === 46 && body.charCodeAt(pos + 2) === 46 ) { return new Token(TokenKind.SPREAD, pos, pos + 3, line, col, prev); } + break; - case 58: // : + case 58: + // : return new Token(TokenKind.COLON, pos, pos + 1, line, col, prev); - case 61: // = + case 61: + // = return new Token(TokenKind.EQUALS, pos, pos + 1, line, col, prev); - case 64: // @ + case 64: + // @ return new Token(TokenKind.AT, pos, pos + 1, line, col, prev); - case 91: // [ + case 91: + // [ return new Token(TokenKind.BRACKET_L, pos, pos + 1, line, col, prev); - case 93: // ] + case 93: + // ] return new Token(TokenKind.BRACKET_R, pos, pos + 1, line, col, prev); - case 123: // { + case 123: + // { return new Token(TokenKind.BRACE_L, pos, pos + 1, line, col, prev); - case 124: // | + case 124: + // | return new Token(TokenKind.PIPE, pos, pos + 1, line, col, prev); - case 125: // } + case 125: + // } return new Token(TokenKind.BRACE_R, pos, pos + 1, line, col, prev); - case 34: // " + case 34: + // " if ( body.charCodeAt(pos + 1) === 34 && body.charCodeAt(pos + 2) === 34 ) { return readBlockString(source, pos, line, col, prev, lexer); } + return readString(source, pos, line, col, prev); - case 45: // - - case 48: // 0 - case 49: // 1 - case 50: // 2 - case 51: // 3 - case 52: // 4 - case 53: // 5 - case 54: // 6 - case 55: // 7 - case 56: // 8 - case 57: // 9 + case 45: + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + // 9 return readNumber(source, pos, code, line, col, prev); - case 65: // A - case 66: // B - case 67: // C - case 68: // D - case 69: // E - case 70: // F - case 71: // G - case 72: // H - case 73: // I - case 74: // J - case 75: // K - case 76: // L - case 77: // M - case 78: // N - case 79: // O - case 80: // P - case 81: // Q - case 82: // R - case 83: // S - case 84: // T - case 85: // U - case 86: // V - case 87: // W - case 88: // X - case 89: // Y - case 90: // Z - case 95: // _ - case 97: // a - case 98: // b - case 99: // c - case 100: // d - case 101: // e - case 102: // f - case 103: // g - case 104: // h - case 105: // i - case 106: // j - case 107: // k - case 108: // l - case 109: // m - case 110: // n - case 111: // o - case 112: // p - case 113: // q - case 114: // r - case 115: // s - case 116: // t - case 117: // u - case 118: // v - case 119: // w - case 120: // x - case 121: // y - case 122: // z + case 65: + case 66: + case 67: + case 68: + case 69: + case 70: + case 71: + case 72: + case 73: + case 74: + case 75: + case 76: + case 77: + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + case 90: + case 95: + case 97: + case 98: + case 99: + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + case 108: + case 109: + case 110: + case 111: + case 112: + case 113: + case 114: + case 115: + case 116: + case 117: + case 118: + case 119: + case 120: + case 121: + case 122: + // z return readName(source, pos, line, col, prev); } @@ -303,8 +325,7 @@ function readComment( do { code = body.charCodeAt(++position); } while ( - !isNaN(code) && - // SourceCharacter but not LineTerminator + !isNaN(code) && // SourceCharacter but not LineTerminator (code > 0x001f || code === 0x0009) ); @@ -442,8 +463,7 @@ function readString( while ( position < body.length && - !isNaN((code = body.charCodeAt(position))) && - // not LineTerminator + !isNaN((code = body.charCodeAt(position))) && // not LineTerminator code !== 0x000a && code !== 0x000d ) { diff --git a/src/language/location.js b/src/language/location.ts similarity index 81% rename from src/language/location.js rename to src/language/location.ts index 8da175d4f2c..56b3b197c90 100644 --- a/src/language/location.js +++ b/src/language/location.ts @@ -1,12 +1,12 @@ -import type { Source } from './source'; +import { Source } from './source'; /** * Represents a location in a Source. */ -export type SourceLocation = {| - +line: number, - +column: number, -|}; +export type SourceLocation = { + readonly line: number; + readonly column: number; +}; /** * Takes a Source and a UTF-8 character offset, and returns the corresponding diff --git a/src/language/parser.js b/src/language/parser.ts similarity index 98% rename from src/language/parser.js rename to src/language/parser.ts index 2f1ff298287..d30d7a327ec 100644 --- a/src/language/parser.js +++ b/src/language/parser.ts @@ -1,8 +1,8 @@ -import type { GraphQLError } from '../error/GraphQLError'; +import { GraphQLError } from '../error/GraphQLError'; import { syntaxError } from '../error/syntaxError'; -import type { TokenKindEnum } from './tokenKind'; -import type { +import { TokenKindEnum } from './tokenKind'; +import { Token, NameNode, VariableNode, @@ -58,13 +58,13 @@ import { Lexer, isPunctuatorTokenKind } from './lexer'; /** * Configuration options to control parser behavior */ -export type ParseOptions = {| +export type ParseOptions = { /** * By default, the parser creates AST nodes that know the location * in the source that they correspond to. This configuration flag * disables that behavior for performance or testing. */ - noLocation?: boolean, + noLocation?: boolean; /** * EXPERIMENTAL: @@ -82,8 +82,8 @@ export type ParseOptions = {| * Note: this feature is experimental and may change or be removed in the * future. */ - experimentalFragmentVariables?: boolean, -|}; + experimentalFragmentVariables?: boolean; +}; /** * Given a GraphQL source, parses it into a Document. @@ -151,7 +151,7 @@ export function parseType( * @internal */ export class Parser { - _options: ?ParseOptions; + _options: ParseOptions | null | undefined; _lexer: Lexer; constructor(source: string | Source, options?: ParseOptions) { @@ -168,7 +168,7 @@ export class Parser { const token = this.expectToken(TokenKind.NAME); return { kind: Kind.NAME, - value: ((token.value: any): string), + value: (token.value as any) as string, loc: this.loc(token), }; } @@ -521,16 +521,18 @@ export class Parser { return this.parseObject(isConst); case TokenKind.INT: this._lexer.advance(); + return { kind: Kind.INT, - value: ((token.value: any): string), + value: (token.value as any) as string, loc: this.loc(token), }; case TokenKind.FLOAT: this._lexer.advance(); + return { kind: Kind.FLOAT, - value: ((token.value: any): string), + value: (token.value as any) as string, loc: this.loc(token), }; case TokenKind.STRING: @@ -538,6 +540,7 @@ export class Parser { return this.parseStringLiteral(); case TokenKind.NAME: this._lexer.advance(); + switch (token.value) { case 'true': return { kind: Kind.BOOLEAN, value: true, loc: this.loc(token) }; @@ -548,14 +551,16 @@ export class Parser { default: return { kind: Kind.ENUM, - value: ((token.value: any): string), + value: (token.value as any) as string, loc: this.loc(token), }; } + case TokenKind.DOLLAR: if (!isConst) { return this.parseVariable(); } + break; } throw this.unexpected(); @@ -566,7 +571,7 @@ export class Parser { this._lexer.advance(); return { kind: Kind.STRING, - value: ((token.value: any): string), + value: (token.value as any) as string, block: token.kind === TokenKind.BLOCK_STRING, loc: this.loc(token), }; @@ -1382,7 +1387,7 @@ export class Parser { * If the next token is of the given kind, return that token after advancing the lexer. * Otherwise, do not change the parser state and return undefined. */ - expectOptionalToken(kind: TokenKindEnum): ?Token { + expectOptionalToken(kind: TokenKindEnum): Token | null | undefined { const token = this._lexer.token; if (token.kind === kind) { this._lexer.advance(); @@ -1424,7 +1429,7 @@ export class Parser { /** * Helper function for creating an error when an unexpected lexed token is encountered. */ - unexpected(atToken?: ?Token): GraphQLError { + unexpected(atToken?: Token | null | undefined): GraphQLError { const token = atToken ?? this._lexer.token; return syntaxError( this._lexer.source, diff --git a/src/language/predicates.js b/src/language/predicates.ts similarity index 79% rename from src/language/predicates.js rename to src/language/predicates.ts index b9108f87ade..bf7736ec49f 100644 --- a/src/language/predicates.js +++ b/src/language/predicates.ts @@ -1,7 +1,7 @@ -import type { ASTNode } from './ast'; +import { ASTNode } from './ast'; import { Kind } from './kinds'; -export function isDefinitionNode(node: ASTNode): boolean %checks { +export function isDefinitionNode(node: ASTNode): boolean { return ( isExecutableDefinitionNode(node) || isTypeSystemDefinitionNode(node) || @@ -9,14 +9,14 @@ export function isDefinitionNode(node: ASTNode): boolean %checks { ); } -export function isExecutableDefinitionNode(node: ASTNode): boolean %checks { +export function isExecutableDefinitionNode(node: ASTNode): boolean { return ( node.kind === Kind.OPERATION_DEFINITION || node.kind === Kind.FRAGMENT_DEFINITION ); } -export function isSelectionNode(node: ASTNode): boolean %checks { +export function isSelectionNode(node: ASTNode): boolean { return ( node.kind === Kind.FIELD || node.kind === Kind.FRAGMENT_SPREAD || @@ -24,7 +24,7 @@ export function isSelectionNode(node: ASTNode): boolean %checks { ); } -export function isValueNode(node: ASTNode): boolean %checks { +export function isValueNode(node: ASTNode): boolean { return ( node.kind === Kind.VARIABLE || node.kind === Kind.INT || @@ -38,7 +38,7 @@ export function isValueNode(node: ASTNode): boolean %checks { ); } -export function isTypeNode(node: ASTNode): boolean %checks { +export function isTypeNode(node: ASTNode): boolean { return ( node.kind === Kind.NAMED_TYPE || node.kind === Kind.LIST_TYPE || @@ -46,7 +46,7 @@ export function isTypeNode(node: ASTNode): boolean %checks { ); } -export function isTypeSystemDefinitionNode(node: ASTNode): boolean %checks { +export function isTypeSystemDefinitionNode(node: ASTNode): boolean { return ( node.kind === Kind.SCHEMA_DEFINITION || isTypeDefinitionNode(node) || @@ -54,7 +54,7 @@ export function isTypeSystemDefinitionNode(node: ASTNode): boolean %checks { ); } -export function isTypeDefinitionNode(node: ASTNode): boolean %checks { +export function isTypeDefinitionNode(node: ASTNode): boolean { return ( node.kind === Kind.SCALAR_TYPE_DEFINITION || node.kind === Kind.OBJECT_TYPE_DEFINITION || @@ -65,11 +65,11 @@ export function isTypeDefinitionNode(node: ASTNode): boolean %checks { ); } -export function isTypeSystemExtensionNode(node: ASTNode): boolean %checks { +export function isTypeSystemExtensionNode(node: ASTNode): boolean { return node.kind === Kind.SCHEMA_EXTENSION || isTypeExtensionNode(node); } -export function isTypeExtensionNode(node: ASTNode): boolean %checks { +export function isTypeExtensionNode(node: ASTNode): boolean { return ( node.kind === Kind.SCALAR_TYPE_EXTENSION || node.kind === Kind.OBJECT_TYPE_EXTENSION || diff --git a/src/language/printLocation.js b/src/language/printLocation.ts similarity index 92% rename from src/language/printLocation.js rename to src/language/printLocation.ts index fbf35046340..135e779eef6 100644 --- a/src/language/printLocation.js +++ b/src/language/printLocation.ts @@ -1,6 +1,6 @@ -import type { Source } from './source'; -import type { Location } from './ast'; -import type { SourceLocation } from './location'; +import { Source } from './source'; +import { Location } from './ast'; +import { SourceLocation } from './location'; import { getLocation } from './location'; /** @@ -66,7 +66,7 @@ export function printSourceLocation( ); } -function printPrefixedLines(lines: $ReadOnlyArray<[string, string]>): string { +function printPrefixedLines(lines: ReadonlyArray<[string, string]>): string { const existingLines = lines.filter(([_, line]) => line !== undefined); const padLen = Math.max(...existingLines.map(([prefix]) => prefix.length)); diff --git a/src/language/printer.js b/src/language/printer.ts similarity index 93% rename from src/language/printer.js rename to src/language/printer.ts index 8ca8fb2dad6..c524281fece 100644 --- a/src/language/printer.js +++ b/src/language/printer.ts @@ -1,4 +1,4 @@ -import type { ASTNode } from './ast'; +import { ASTNode } from './ast'; import { visit } from './visitor'; import { printBlockString } from './blockString'; @@ -67,14 +67,9 @@ const printDocASTReducer: any = { ' ', ), - FragmentDefinition: ({ - name, - typeCondition, - variableDefinitions, - directives, - selectionSet, - }) => - // Note: fragment variable definitions are experimental and may be changed + FragmentDefinition: ( + { name, typeCondition, variableDefinitions, directives, selectionSet }, // Note: fragment variable definitions are experimental and may be changed + ) => // or removed in the future. `fragment ${name}${wrap('(', join(variableDefinitions, ', '), ')')} ` + `on ${typeCondition} ${wrap('', join(directives, ' '), ' ')}` + @@ -257,7 +252,10 @@ function addDescription(cb) { * Given maybeArray, print an empty string if it is null or empty, otherwise * print all items together separated by separator if provided */ -function join(maybeArray: ?Array, separator = ''): string { +function join( + maybeArray: Array | null | undefined, + separator = '', +): string { return maybeArray?.filter((x) => x).join(separator) ?? ''; } @@ -265,14 +263,18 @@ function join(maybeArray: ?Array, separator = ''): string { * Given array, print each item on its own line, wrapped in an * indented "{ }" block. */ -function block(array: ?Array): string { +function block(array: Array | null | undefined): string { return wrap('{\n', indent(join(array, '\n')), '\n}'); } /** * If maybeString is not null or empty, then wrap with start and end, otherwise print an empty string. */ -function wrap(start: string, maybeString: ?string, end: string = ''): string { +function wrap( + start: string, + maybeString: string | null | undefined, + end: string = '', +): string { return maybeString != null && maybeString !== '' ? start + maybeString + end : ''; @@ -286,6 +288,8 @@ function isMultiline(str: string): boolean { return str.indexOf('\n') !== -1; } -function hasMultilineItems(maybeArray: ?Array): boolean { +function hasMultilineItems( + maybeArray: Array | null | undefined, +): boolean { return maybeArray != null && maybeArray.some(isMultiline); } diff --git a/src/language/source.js b/src/language/source.ts similarity index 91% rename from src/language/source.js rename to src/language/source.ts index 01f45fba448..4b4faf1e36d 100644 --- a/src/language/source.js +++ b/src/language/source.ts @@ -2,10 +2,10 @@ import inspect from '../jsutils/inspect'; import devAssert from '../jsutils/devAssert'; import instanceOf from '../jsutils/instanceOf'; -type Location = {| - line: number, - column: number, -|}; +type Location = { + line: number; + column: number; +}; /** * A representation of source input to GraphQL. The `name` and `locationOffset` parameters are @@ -53,8 +53,7 @@ export class Source { * * @internal */ -declare function isSource(source: mixed): boolean %checks(source instanceof - Source); +declare function isSource(source: unknown): boolean; // eslint-disable-next-line no-redeclare export function isSource(source) { return instanceOf(source, Source); diff --git a/src/language/tokenKind.js b/src/language/tokenKind.ts similarity index 93% rename from src/language/tokenKind.js rename to src/language/tokenKind.ts index b4f5248c133..c8015737b64 100644 --- a/src/language/tokenKind.js +++ b/src/language/tokenKind.ts @@ -1,3 +1,5 @@ +import { $Values } from 'utility-types'; + /** * An exported enum describing the different kinds of tokens that the * lexer emits. diff --git a/src/language/visitor.js b/src/language/visitor.ts similarity index 89% rename from src/language/visitor.js rename to src/language/visitor.ts index 5e367ce4a96..69b80a29b0e 100644 --- a/src/language/visitor.js +++ b/src/language/visitor.ts @@ -1,6 +1,7 @@ +import { $Values, $Shape, $Keys } from 'utility-types'; import inspect from '../jsutils/inspect'; -import type { ASTNode, ASTKindToNode } from './ast'; +import { ASTNode, ASTKindToNode } from './ast'; import { isNode } from './ast'; /** @@ -11,32 +12,30 @@ export type ASTVisitor = Visitor; export type Visitor> = | EnterLeave< | VisitFn - | ShapeMap(Node) => VisitFn>, + | ShapeMap(arg0: Node) => VisitFn> > | ShapeMap< KindToNode, - (Node) => VisitFn | EnterLeave>, + ( + arg0: Node, + ) => VisitFn | EnterLeave> >; -type EnterLeave = {| +enter?: T, +leave?: T |}; +type EnterLeave = { readonly enter?: T; readonly leave?: T }; type ShapeMap = $Shape<$ObjMap>; /** * A visitor is comprised of visit functions, which are called on each node * during the visitor's traversal. */ -export type VisitFn = ( +export type VisitFn = ( // The current node being visiting. - node: TVisitedNode, - // The index or key to this node from the parent node or Array. - key: string | number | void, - // The parent immediately above this node, which may be an Array. - parent: TAnyNode | $ReadOnlyArray | void, - // The key path to get to this node from the root node. - path: $ReadOnlyArray, - // All nodes and Arrays visited before reaching parent of this node. + node: TVisitedNode, // The index or key to this node from the parent node or Array. + key: string | number | void, // The parent immediately above this node, which may be an Array. + parent: TAnyNode | ReadonlyArray | void, // The key path to get to this node from the root node. + path: ReadonlyArray, // All nodes and Arrays visited before reaching parent of this node. // These correspond to array indices in `path`. // Note: ancestors includes arrays which contain the parent of visited node. - ancestors: $ReadOnlyArray>, + ancestors: ReadonlyArray>, ) => any; /** @@ -44,7 +43,7 @@ export type VisitFn = ( */ export type VisitorKeyMap = $ObjMap< KindToNode, - (T) => $ReadOnlyArray<$Keys>, + (arg0: T) => ReadonlyArray<$Keys> >; export const QueryDocumentKeys: VisitorKeyMap = { @@ -66,8 +65,7 @@ export const QueryDocumentKeys: VisitorKeyMap = { FragmentSpread: ['name', 'directives'], InlineFragment: ['typeCondition', 'directives', 'selectionSet'], FragmentDefinition: [ - 'name', - // Note: fragment variable definitions are experimental and may be changed + 'name', // Note: fragment variable definitions are experimental and may be changed // or removed in the future. 'variableDefinitions', 'typeCondition', @@ -134,7 +132,7 @@ export const QueryDocumentKeys: VisitorKeyMap = { InputObjectTypeExtension: ['name', 'directives', 'fields'], }; -export const BREAK: { ... } = Object.freeze({}); +export const BREAK: {} = Object.freeze({}); /** * visit() will walk through an AST using a depth-first traversal, calling @@ -239,6 +237,7 @@ export function visit( const path: any = []; const ancestors = []; let newRoot = root; + /* eslint-enable no-undef-init */ do { @@ -355,7 +354,7 @@ export function visit( * If a prior visitor edits a node, no following visitors will see that node. */ export function visitInParallel( - visitors: $ReadOnlyArray>, + visitors: ReadonlyArray>, ): Visitor { const skipping = new Array(visitors.length); @@ -363,7 +362,12 @@ export function visitInParallel( enter(node) { for (let i = 0; i < visitors.length; i++) { if (skipping[i] == null) { - const fn = getVisitFn(visitors[i], node.kind, /* isLeaving */ false); + const fn = getVisitFn( + visitors[i], + node.kind, + /* isLeaving */ + false, + ); if (fn) { const result = fn.apply(visitors[i], arguments); if (result === false) { @@ -380,7 +384,12 @@ export function visitInParallel( leave(node) { for (let i = 0; i < visitors.length; i++) { if (skipping[i] == null) { - const fn = getVisitFn(visitors[i], node.kind, /* isLeaving */ true); + const fn = getVisitFn( + visitors[i], + node.kind, + /* isLeaving */ + true, + ); if (fn) { const result = fn.apply(visitors[i], arguments); if (result === BREAK) { @@ -405,7 +414,7 @@ export function getVisitFn( visitor: Visitor, kind: string, isLeaving: boolean, -): ?VisitFn { +): VisitFn | null | undefined { const kindVisitor = visitor[kind]; if (kindVisitor) { if (!isLeaving && typeof kindVisitor === 'function') { diff --git a/src/polyfills/objectEntries.js b/src/polyfills/objectEntries.ts similarity index 62% rename from src/polyfills/objectEntries.js rename to src/polyfills/objectEntries.ts index 30e55852723..6c41ad18be5 100644 --- a/src/polyfills/objectEntries.js +++ b/src/polyfills/objectEntries.ts @@ -1,9 +1,9 @@ -import type { ObjMap } from '../jsutils/ObjMap'; +import { ObjMap } from '../jsutils/ObjMap'; declare function objectEntries(obj: ObjMap): Array<[string, T]>; /* eslint-disable no-redeclare */ -// $FlowFixMe[name-already-bound] workaround for: https://github.com/facebook/flow/issues/4441 + const objectEntries = Object.entries || ((obj) => Object.keys(obj).map((key) => [key, obj[key]])); diff --git a/src/polyfills/objectValues.js b/src/polyfills/objectValues.ts similarity index 60% rename from src/polyfills/objectValues.js rename to src/polyfills/objectValues.ts index 943362a6407..cafb7c85757 100644 --- a/src/polyfills/objectValues.js +++ b/src/polyfills/objectValues.ts @@ -1,9 +1,9 @@ -import type { ObjMap } from '../jsutils/ObjMap'; +import { ObjMap } from '../jsutils/ObjMap'; declare function objectValues(obj: ObjMap): Array; /* eslint-disable no-redeclare */ -// $FlowFixMe[name-already-bound] workaround for: https://github.com/facebook/flow/issues/4441 + const objectValues = Object.values || ((obj) => Object.keys(obj).map((key) => obj[key])); export default objectValues; diff --git a/src/subscription/__tests__/mapAsyncIterator-test.js b/src/subscription/__tests__/mapAsyncIterator-test.ts similarity index 98% rename from src/subscription/__tests__/mapAsyncIterator-test.js rename to src/subscription/__tests__/mapAsyncIterator-test.ts index 4af866f20aa..c47555397c9 100644 --- a/src/subscription/__tests__/mapAsyncIterator-test.js +++ b/src/subscription/__tests__/mapAsyncIterator-test.ts @@ -298,7 +298,7 @@ describe('mapAsyncIterator', () => { }); }); - async function testClosesSourceWithMapper(mapper: (number) => T) { + async function testClosesSourceWithMapper(mapper: (arg0: number) => T) { let didVisitFinally = false; async function* source() { @@ -354,7 +354,9 @@ describe('mapAsyncIterator', () => { ); }); - async function testClosesSourceWithRejectMapper(mapper: (Error) => T) { + async function testClosesSourceWithRejectMapper( + mapper: (arg0: Error) => T, + ) { async function* source() { yield 1; throw new Error(2); diff --git a/src/subscription/__tests__/simplePubSub-test.js b/src/subscription/__tests__/simplePubSub-test.ts similarity index 100% rename from src/subscription/__tests__/simplePubSub-test.js rename to src/subscription/__tests__/simplePubSub-test.ts diff --git a/src/subscription/__tests__/simplePubSub.js b/src/subscription/__tests__/simplePubSub.ts similarity index 90% rename from src/subscription/__tests__/simplePubSub.js rename to src/subscription/__tests__/simplePubSub.ts index e12c93d0b9d..a02a9def01f 100644 --- a/src/subscription/__tests__/simplePubSub.js +++ b/src/subscription/__tests__/simplePubSub.ts @@ -3,7 +3,7 @@ * PubSub system for tests. */ export default class SimplePubSub { - _subscribers: Set<(T) => void>; + _subscribers: Set<(arg0: T) => void>; constructor() { this._subscribers = new Set(); @@ -16,7 +16,7 @@ export default class SimplePubSub { return this._subscribers.size > 0; } - getSubscriber(transform?: (T) => R): AsyncGenerator { + getSubscriber(transform?: (arg0: T) => R): AsyncGenerator { const pullQueue = []; const pushQueue = []; let listening = true; @@ -34,7 +34,7 @@ export default class SimplePubSub { /* TODO: Flow doesn't support symbols as keys: https://github.com/facebook/flow/issues/3258 */ - return ({ + return { next() { if (!listening) { return Promise.resolve({ value: undefined, done: true }); @@ -49,14 +49,14 @@ export default class SimplePubSub { emptyQueue(); return Promise.resolve({ value: undefined, done: true }); }, - throw(error: mixed) { + throw(error: unknown) { emptyQueue(); return Promise.reject(error); }, [Symbol.asyncIterator]() { return this; }, - }: any); + } as any; function pushValue(event: T): void { const value = transform != null ? transform(event) : event; diff --git a/src/subscription/__tests__/subscribe-test.js b/src/subscription/__tests__/subscribe-test.ts similarity index 98% rename from src/subscription/__tests__/subscribe-test.js rename to src/subscription/__tests__/subscribe-test.ts index c0cc0ce8513..f7e09679cd8 100644 --- a/src/subscription/__tests__/subscribe-test.js +++ b/src/subscription/__tests__/subscribe-test.ts @@ -6,7 +6,7 @@ import resolveOnNextTick from '../../__testUtils__/resolveOnNextTick'; import invariant from '../../jsutils/invariant'; import isAsyncIterable from '../../jsutils/isAsyncIterable'; -import type { DocumentNode } from '../../language/ast'; +import { DocumentNode } from '../../language/ast'; import { parse } from '../../language/parser'; import { GraphQLError } from '../../error/GraphQLError'; @@ -19,12 +19,12 @@ import { createSourceEventStream, subscribe } from '../subscribe'; import SimplePubSub from './simplePubSub'; -type Email = {| - from: string, - subject: string, - message: string, - unread: boolean, -|}; +type Email = { + from: string; + subject: string; + message: string; + unread: boolean; +}; const EmailType = new GraphQLObjectType({ name: 'Email', @@ -68,9 +68,9 @@ const EmailEventType = new GraphQLObjectType({ const emailSchema = emailSchemaWithResolvers(); -function emailSchemaWithResolvers( - subscribeFn?: (T) => mixed, - resolveFn?: (T) => mixed, +function emailSchemaWithResolvers( + subscribeFn?: (arg0: T) => unknown, + resolveFn?: (arg0: T) => unknown, ) { return new GraphQLSchema({ query: QueryType, @@ -137,7 +137,7 @@ function createSubscription( } async function expectPromiseToThrow( - promise: () => Promise, + promise: () => Promise, message: string, ) { try { diff --git a/src/subscription/index.js b/src/subscription/index.ts similarity index 55% rename from src/subscription/index.js rename to src/subscription/index.ts index 899e443b6b9..971b34dbbb3 100644 --- a/src/subscription/index.js +++ b/src/subscription/index.ts @@ -1,2 +1,2 @@ export { subscribe, createSourceEventStream } from './subscribe'; -export type { SubscriptionArgs } from './subscribe'; +export { SubscriptionArgs } from './subscribe'; diff --git a/src/subscription/mapAsyncIterator.js b/src/subscription/mapAsyncIterator.ts similarity index 83% rename from src/subscription/mapAsyncIterator.js rename to src/subscription/mapAsyncIterator.ts index 5a64de54f1c..247c63f1cc7 100644 --- a/src/subscription/mapAsyncIterator.js +++ b/src/subscription/mapAsyncIterator.ts @@ -1,4 +1,4 @@ -import type { PromiseOrValue } from '../jsutils/PromiseOrValue'; +import { PromiseOrValue } from '../jsutils/PromiseOrValue'; /** * Given an AsyncIterable and a callback function, return an AsyncIterator @@ -6,8 +6,8 @@ import type { PromiseOrValue } from '../jsutils/PromiseOrValue'; */ export default function mapAsyncIterator( iterable: AsyncIterable | AsyncGenerator, - callback: (T) => PromiseOrValue, - rejectCallback?: (any) => PromiseOrValue, + callback: (arg0: T) => PromiseOrValue, + rejectCallback?: (arg0: any) => PromiseOrValue, ): AsyncGenerator { // $FlowFixMe[prop-missing] const iteratorMethod = iterable[Symbol.asyncIterator]; @@ -16,7 +16,7 @@ export default function mapAsyncIterator( let abruptClose; if (typeof iterator.return === 'function') { $return = iterator.return; - abruptClose = (error: mixed) => { + abruptClose = (error: unknown) => { const rethrow = () => Promise.reject(error); return $return.call(iterator).then(rethrow, rethrow); }; @@ -32,13 +32,13 @@ export default function mapAsyncIterator( if (rejectCallback) { // Capture rejectCallback to ensure it cannot be null. const reject = rejectCallback; - mapReject = (error: mixed) => + mapReject = (error: unknown) => asyncMapValue(error, reject).then(iteratorResult, abruptClose); } /* TODO: Flow doesn't support symbols as keys: https://github.com/facebook/flow/issues/3258 */ - return ({ + return { next(): Promise> { return iterator.next().then(mapResult, mapReject); }, @@ -47,7 +47,7 @@ export default function mapAsyncIterator( ? $return.call(iterator).then(mapResult, mapReject) : Promise.resolve({ value: undefined, done: true }); }, - throw(error?: mixed): Promise> { + throw(error?: unknown): Promise> { if (typeof iterator.throw === 'function') { return iterator.throw(error).then(mapResult, mapReject); } @@ -56,12 +56,12 @@ export default function mapAsyncIterator( [Symbol.asyncIterator]() { return this; }, - }: $FlowFixMe); + } as $FlowFixMe; } function asyncMapValue( value: T, - callback: (T) => PromiseOrValue, + callback: (arg0: T) => PromiseOrValue, ): Promise { return new Promise((resolve) => resolve(callback(value))); } diff --git a/src/subscription/subscribe.js b/src/subscription/subscribe.ts similarity index 86% rename from src/subscription/subscribe.js rename to src/subscription/subscribe.ts index 4ff1b9d72a3..3ba09d91dc0 100644 --- a/src/subscription/subscribe.js +++ b/src/subscription/subscribe.ts @@ -5,9 +5,9 @@ import { addPath, pathToArray } from '../jsutils/Path'; import { GraphQLError } from '../error/GraphQLError'; import { locatedError } from '../error/locatedError'; -import type { DocumentNode } from '../language/ast'; +import { DocumentNode } from '../language/ast'; -import type { ExecutionResult, ExecutionContext } from '../execution/execute'; +import { ExecutionResult, ExecutionContext } from '../execution/execute'; import { getArgumentValues } from '../execution/values'; import { assertValidExecutionArguments, @@ -18,23 +18,28 @@ import { getFieldDef, } from '../execution/execute'; -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLFieldResolver } from '../type/definition'; +import { GraphQLSchema } from '../type/schema'; +import { GraphQLFieldResolver } from '../type/definition'; import { getOperationRootType } from '../utilities/getOperationRootType'; import mapAsyncIterator from './mapAsyncIterator'; -export type SubscriptionArgs = {| - schema: GraphQLSchema, - document: DocumentNode, - rootValue?: mixed, - contextValue?: mixed, - variableValues?: ?{ +[variable: string]: mixed, ... }, - operationName?: ?string, - fieldResolver?: ?GraphQLFieldResolver, - subscribeFieldResolver?: ?GraphQLFieldResolver, -|}; +export type SubscriptionArgs = { + schema: GraphQLSchema; + document: DocumentNode; + rootValue?: unknown; + contextValue?: unknown; + variableValues?: + | { + readonly [variable: string]: unknown; + } + | null + | undefined; + operationName?: string | null | undefined; + fieldResolver?: GraphQLFieldResolver | null | undefined; + subscribeFieldResolver?: GraphQLFieldResolver | null | undefined; +}; /** * Implements the "Subscribe" algorithm described in the GraphQL specification. @@ -100,15 +105,16 @@ export function subscribe( // Resolve the Source Stream, then map every source value to a // ExecutionResult value as described above. - return sourcePromise.then((resultOrStream) => - // Note: Flow can't refine isAsyncIterable, so explicit casts are used. + return sourcePromise.then(( + resultOrStream, // Note: Flow can't refine isAsyncIterable, so explicit casts are used. + ) => isAsyncIterable(resultOrStream) ? mapAsyncIterator( resultOrStream, mapSourceToResponse, reportGraphQLError, ) - : ((resultOrStream: any): ExecutionResult), + : ((resultOrStream as any) as ExecutionResult), ); } @@ -117,7 +123,7 @@ export function subscribe( * an ExecutionResult, containing only errors and no data. Otherwise treat the * error as a system-class error and re-throw it. */ -function reportGraphQLError(error: mixed): ExecutionResult { +function reportGraphQLError(error: unknown): ExecutionResult { if (error instanceof GraphQLError) { return { errors: [error] }; } @@ -155,12 +161,17 @@ function reportGraphQLError(error: mixed): ExecutionResult { export function createSourceEventStream( schema: GraphQLSchema, document: DocumentNode, - rootValue?: mixed, - contextValue?: mixed, - variableValues?: ?{ +[variable: string]: mixed, ... }, - operationName?: ?string, - fieldResolver?: ?GraphQLFieldResolver, -): Promise | ExecutionResult> { + rootValue?: unknown, + contextValue?: unknown, + variableValues?: + | { + readonly [variable: string]: unknown; + } + | null + | undefined, + operationName?: string | null | undefined, + fieldResolver?: GraphQLFieldResolver | null | undefined, +): Promise | ExecutionResult> { // If arguments are missing or incorrectly typed, this is an internal // developer mistake which should throw an early error. assertValidExecutionArguments(schema, document, variableValues); @@ -189,7 +200,7 @@ export function createSourceEventStream( function executeSubscription( exeContext: ExecutionContext, -): Promise> { +): Promise> { const { schema, operation, variableValues, rootValue } = exeContext; const type = getOperationRootType(schema, operation); const fields = collectFields( diff --git a/src/type/__tests__/definition-test.js b/src/type/__tests__/definition-test.ts similarity index 99% rename from src/type/__tests__/definition-test.js rename to src/type/__tests__/definition-test.ts index 65b176d150f..4b4bba7874e 100644 --- a/src/type/__tests__/definition-test.js +++ b/src/type/__tests__/definition-test.ts @@ -6,7 +6,7 @@ import identityFunc from '../../jsutils/identityFunc'; import { parseValue } from '../../language/parser'; -import type { GraphQLType, GraphQLNullableType } from '../definition'; +import { GraphQLType, GraphQLNullableType } from '../definition'; import { GraphQLList, GraphQLNonNull, @@ -922,7 +922,7 @@ describe('Type System: test utility methods', () => { }); it('Object.toStringifies types', () => { - function toString(obj: mixed): string { + function toString(obj: unknown): string { return Object.prototype.toString.call(obj); } diff --git a/src/type/__tests__/directive-test.js b/src/type/__tests__/directive-test.ts similarity index 100% rename from src/type/__tests__/directive-test.js rename to src/type/__tests__/directive-test.ts diff --git a/src/type/__tests__/enumType-test.js b/src/type/__tests__/enumType-test.ts similarity index 99% rename from src/type/__tests__/enumType-test.js rename to src/type/__tests__/enumType-test.ts index 0145657733f..f083b845928 100644 --- a/src/type/__tests__/enumType-test.js +++ b/src/type/__tests__/enumType-test.ts @@ -114,7 +114,9 @@ const schema = new GraphQLSchema({ function executeQuery( source: string, - variableValues?: { +[variable: string]: mixed, ... }, + variableValues?: { + readonly [variable: string]: unknown; + }, ) { return graphqlSync({ schema, source, variableValues }); } diff --git a/src/type/__tests__/extensions-test.js b/src/type/__tests__/extensions-test.ts similarity index 99% rename from src/type/__tests__/extensions-test.js rename to src/type/__tests__/extensions-test.ts index 76dd0ee233e..792e962b7d9 100644 --- a/src/type/__tests__/extensions-test.js +++ b/src/type/__tests__/extensions-test.ts @@ -16,7 +16,7 @@ import { const dummyType = new GraphQLScalarType({ name: 'DummyScalar' }); -function expectObjMap(value: mixed) { +function expectObjMap(value: unknown) { invariant(value != null && typeof value === 'object'); expect(Object.getPrototypeOf(value)).to.equal(null); return expect(value); diff --git a/src/type/__tests__/introspection-test.js b/src/type/__tests__/introspection-test.ts similarity index 100% rename from src/type/__tests__/introspection-test.js rename to src/type/__tests__/introspection-test.ts diff --git a/src/type/__tests__/predicate-test.js b/src/type/__tests__/predicate-test.ts similarity index 98% rename from src/type/__tests__/predicate-test.js rename to src/type/__tests__/predicate-test.ts index 33c2c49f579..83d98580688 100644 --- a/src/type/__tests__/predicate-test.js +++ b/src/type/__tests__/predicate-test.ts @@ -1,7 +1,8 @@ +import { $Shape } from 'utility-types'; import { expect } from 'chai'; import { describe, it } from 'mocha'; -import type { GraphQLArgument, GraphQLInputField } from '../definition'; +import { GraphQLArgument, GraphQLInputField } from '../definition'; import { GraphQLDirective, GraphQLSkipDirective, @@ -296,7 +297,7 @@ describe('Type predicates', () => { }); describe('isInputType', () => { - function expectInputType(type: mixed) { + function expectInputType(type: unknown) { expect(isInputType(type)).to.equal(true); expect(() => assertInputType(type)).to.not.throw(); } @@ -317,7 +318,7 @@ describe('Type predicates', () => { expectInputType(new GraphQLNonNull(InputObjectType)); }); - function expectNonInputType(type: mixed) { + function expectNonInputType(type: unknown) { expect(isInputType(type)).to.equal(false); expect(() => assertInputType(type)).to.throw(); } @@ -340,7 +341,7 @@ describe('Type predicates', () => { }); describe('isOutputType', () => { - function expectOutputType(type: mixed) { + function expectOutputType(type: unknown) { expect(isOutputType(type)).to.equal(true); expect(() => assertOutputType(type)).to.not.throw(); } @@ -367,7 +368,7 @@ describe('Type predicates', () => { expectOutputType(new GraphQLNonNull(EnumType)); }); - function expectNonOutputType(type: mixed) { + function expectNonOutputType(type: unknown) { expect(isOutputType(type)).to.equal(false); expect(() => assertOutputType(type)).to.throw(); } diff --git a/src/type/__tests__/scalars-test.js b/src/type/__tests__/scalars-test.ts similarity index 98% rename from src/type/__tests__/scalars-test.js rename to src/type/__tests__/scalars-test.ts index 6e901c3fb05..67b1610c28f 100644 --- a/src/type/__tests__/scalars-test.js +++ b/src/type/__tests__/scalars-test.ts @@ -14,7 +14,7 @@ import { describe('Type System: Specified scalar types', () => { describe('GraphQLInt', () => { it('parseValue', () => { - function parseValue(value: mixed) { + function parseValue(value: unknown) { return GraphQLInt.parseValue(value); } @@ -110,7 +110,7 @@ describe('Type System: Specified scalar types', () => { }); it('serialize', () => { - function serialize(value: mixed) { + function serialize(value: unknown) { return GraphQLInt.serialize(value); } @@ -183,7 +183,7 @@ describe('Type System: Specified scalar types', () => { describe('GraphQLFloat', () => { it('parseValue', () => { - function parseValue(value: mixed) { + function parseValue(value: unknown) { return GraphQLFloat.parseValue(value); } @@ -270,7 +270,7 @@ describe('Type System: Specified scalar types', () => { }); it('serialize', () => { - function serialize(value: mixed) { + function serialize(value: unknown) { return GraphQLFloat.serialize(value); } @@ -313,7 +313,7 @@ describe('Type System: Specified scalar types', () => { describe('GraphQLString', () => { it('parseValue', () => { - function parseValue(value: mixed) { + function parseValue(value: unknown) { return GraphQLString.parseValue(value); } @@ -377,7 +377,7 @@ describe('Type System: Specified scalar types', () => { }); it('serialize', () => { - function serialize(value: mixed) { + function serialize(value: unknown) { return GraphQLString.serialize(value); } @@ -418,7 +418,7 @@ describe('Type System: Specified scalar types', () => { describe('GraphQLBoolean', () => { it('parseValue', () => { - function parseValue(value: mixed) { + function parseValue(value: unknown) { return GraphQLBoolean.parseValue(value); } @@ -495,7 +495,7 @@ describe('Type System: Specified scalar types', () => { }); it('serialize', () => { - function serialize(value: mixed) { + function serialize(value: unknown) { return GraphQLBoolean.serialize(value); } @@ -532,7 +532,7 @@ describe('Type System: Specified scalar types', () => { describe('GraphQLID', () => { it('parseValue', () => { - function parseValue(value: mixed) { + function parseValue(value: unknown) { return GraphQLID.parseValue(value); } @@ -610,7 +610,7 @@ describe('Type System: Specified scalar types', () => { }); it('serialize', () => { - function serialize(value: mixed) { + function serialize(value: unknown) { return GraphQLID.serialize(value); } diff --git a/src/type/__tests__/schema-test.js b/src/type/__tests__/schema-test.ts similarity index 100% rename from src/type/__tests__/schema-test.js rename to src/type/__tests__/schema-test.ts diff --git a/src/type/__tests__/validation-test.js b/src/type/__tests__/validation-test.ts similarity index 99% rename from src/type/__tests__/validation-test.js rename to src/type/__tests__/validation-test.ts index a3e35443dad..824abe8f04e 100644 --- a/src/type/__tests__/validation-test.js +++ b/src/type/__tests__/validation-test.ts @@ -10,7 +10,7 @@ import { parse } from '../../language/parser'; import { extendSchema } from '../../utilities/extendSchema'; import { buildSchema } from '../../utilities/buildASTSchema'; -import type { +import { GraphQLNamedType, GraphQLInputType, GraphQLOutputType, @@ -68,7 +68,7 @@ const SomeInputObjectType = assertInputObjectType( const SomeDirective = assertDirective(SomeSchema.getDirective('SomeDirective')); -function withModifiers( +function withModifiers( type: T, ): Array | GraphQLNonNull>> { return [ @@ -1007,7 +1007,7 @@ describe('Type System: Enum types must be well defined', () => { describe('Type System: Object fields must have output types', () => { function schemaWithObjectField( - fieldConfig: GraphQLFieldConfig, + fieldConfig: GraphQLFieldConfig, ): GraphQLSchema { const BadObjectType = new GraphQLObjectType({ name: 'BadObject', @@ -1322,7 +1322,7 @@ describe('Type System: Interface extensions should be valid', () => { describe('Type System: Interface fields must have output types', () => { function schemaWithInterfaceField( - fieldConfig: GraphQLFieldConfig, + fieldConfig: GraphQLFieldConfig, ): GraphQLSchema { const fields = { badField: fieldConfig }; diff --git a/src/type/definition.js b/src/type/definition.js deleted file mode 100644 index 0a125cd8322..00000000000 --- a/src/type/definition.js +++ /dev/null @@ -1,1579 +0,0 @@ -import objectEntries from '../polyfills/objectEntries'; - -import type { Path } from '../jsutils/Path'; -import type { PromiseOrValue } from '../jsutils/PromiseOrValue'; -import type { - ObjMap, - ReadOnlyObjMap, - ReadOnlyObjMapLike, -} from '../jsutils/ObjMap'; -import inspect from '../jsutils/inspect'; -import keyMap from '../jsutils/keyMap'; -import mapValue from '../jsutils/mapValue'; -import toObjMap from '../jsutils/toObjMap'; -import devAssert from '../jsutils/devAssert'; -import keyValMap from '../jsutils/keyValMap'; -import instanceOf from '../jsutils/instanceOf'; -import didYouMean from '../jsutils/didYouMean'; -import isObjectLike from '../jsutils/isObjectLike'; -import identityFunc from '../jsutils/identityFunc'; -import suggestionList from '../jsutils/suggestionList'; - -import { GraphQLError } from '../error/GraphQLError'; - -import { Kind } from '../language/kinds'; -import { print } from '../language/printer'; -import type { - ScalarTypeDefinitionNode, - ObjectTypeDefinitionNode, - FieldDefinitionNode, - InputValueDefinitionNode, - InterfaceTypeDefinitionNode, - UnionTypeDefinitionNode, - EnumTypeDefinitionNode, - EnumValueDefinitionNode, - InputObjectTypeDefinitionNode, - ScalarTypeExtensionNode, - ObjectTypeExtensionNode, - InterfaceTypeExtensionNode, - UnionTypeExtensionNode, - EnumTypeExtensionNode, - InputObjectTypeExtensionNode, - OperationDefinitionNode, - FieldNode, - FragmentDefinitionNode, - ValueNode, -} from '../language/ast'; - -import { valueFromASTUntyped } from '../utilities/valueFromASTUntyped'; - -import type { GraphQLSchema } from './schema'; - -// Predicates & Assertions - -/** - * These are all of the possible kinds of types. - */ -export type GraphQLType = - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLInputObjectType - | GraphQLList - | GraphQLNonNull; - -export function isType(type: mixed): boolean %checks { - return ( - isScalarType(type) || - isObjectType(type) || - isInterfaceType(type) || - isUnionType(type) || - isEnumType(type) || - isInputObjectType(type) || - isListType(type) || - isNonNullType(type) - ); -} - -export function assertType(type: mixed): GraphQLType { - if (!isType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL type.`); - } - return type; -} - -/** - * There are predicates for each kind of GraphQL type. - */ - -declare function isScalarType(type: mixed): boolean %checks(type instanceof - GraphQLScalarType); -// eslint-disable-next-line no-redeclare -export function isScalarType(type) { - return instanceOf(type, GraphQLScalarType); -} - -export function assertScalarType(type: mixed): GraphQLScalarType { - if (!isScalarType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL Scalar type.`); - } - return type; -} - -declare function isObjectType(type: mixed): boolean %checks(type instanceof - GraphQLObjectType); -// eslint-disable-next-line no-redeclare -export function isObjectType(type) { - return instanceOf(type, GraphQLObjectType); -} - -export function assertObjectType(type: mixed): GraphQLObjectType { - if (!isObjectType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL Object type.`); - } - return type; -} - -declare function isInterfaceType(type: mixed): boolean %checks(type instanceof - GraphQLInterfaceType); -// eslint-disable-next-line no-redeclare -export function isInterfaceType(type) { - return instanceOf(type, GraphQLInterfaceType); -} - -export function assertInterfaceType(type: mixed): GraphQLInterfaceType { - if (!isInterfaceType(type)) { - throw new Error( - `Expected ${inspect(type)} to be a GraphQL Interface type.`, - ); - } - return type; -} - -declare function isUnionType(type: mixed): boolean %checks(type instanceof - GraphQLUnionType); -// eslint-disable-next-line no-redeclare -export function isUnionType(type) { - return instanceOf(type, GraphQLUnionType); -} - -export function assertUnionType(type: mixed): GraphQLUnionType { - if (!isUnionType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL Union type.`); - } - return type; -} - -declare function isEnumType(type: mixed): boolean %checks(type instanceof - GraphQLEnumType); -// eslint-disable-next-line no-redeclare -export function isEnumType(type) { - return instanceOf(type, GraphQLEnumType); -} - -export function assertEnumType(type: mixed): GraphQLEnumType { - if (!isEnumType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL Enum type.`); - } - return type; -} - -declare function isInputObjectType(type: mixed): boolean %checks(type instanceof - GraphQLInputObjectType); -// eslint-disable-next-line no-redeclare -export function isInputObjectType(type) { - return instanceOf(type, GraphQLInputObjectType); -} - -export function assertInputObjectType(type: mixed): GraphQLInputObjectType { - if (!isInputObjectType(type)) { - throw new Error( - `Expected ${inspect(type)} to be a GraphQL Input Object type.`, - ); - } - return type; -} - -declare function isListType(type: mixed): boolean %checks(type instanceof - GraphQLList); -// eslint-disable-next-line no-redeclare -export function isListType(type) { - return instanceOf(type, GraphQLList); -} - -export function assertListType(type: mixed): GraphQLList { - if (!isListType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL List type.`); - } - return type; -} - -declare function isNonNullType(type: mixed): boolean %checks(type instanceof - GraphQLNonNull); -// eslint-disable-next-line no-redeclare -export function isNonNullType(type) { - return instanceOf(type, GraphQLNonNull); -} - -export function assertNonNullType(type: mixed): GraphQLNonNull { - if (!isNonNullType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL Non-Null type.`); - } - return type; -} - -/** - * These types may be used as input types for arguments and directives. - */ -export type GraphQLInputType = - | GraphQLScalarType - | GraphQLEnumType - | GraphQLInputObjectType - | GraphQLList - | GraphQLNonNull< - | GraphQLScalarType - | GraphQLEnumType - | GraphQLInputObjectType - | GraphQLList, - >; - -export function isInputType(type: mixed): boolean %checks { - return ( - isScalarType(type) || - isEnumType(type) || - isInputObjectType(type) || - (isWrappingType(type) && isInputType(type.ofType)) - ); -} - -export function assertInputType(type: mixed): GraphQLInputType { - if (!isInputType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL input type.`); - } - return type; -} - -/** - * These types may be used as output types as the result of fields. - */ -export type GraphQLOutputType = - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLList - | GraphQLNonNull< - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLList, - >; - -export function isOutputType(type: mixed): boolean %checks { - return ( - isScalarType(type) || - isObjectType(type) || - isInterfaceType(type) || - isUnionType(type) || - isEnumType(type) || - (isWrappingType(type) && isOutputType(type.ofType)) - ); -} - -export function assertOutputType(type: mixed): GraphQLOutputType { - if (!isOutputType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL output type.`); - } - return type; -} - -/** - * These types may describe types which may be leaf values. - */ -export type GraphQLLeafType = GraphQLScalarType | GraphQLEnumType; - -export function isLeafType(type: mixed): boolean %checks { - return isScalarType(type) || isEnumType(type); -} - -export function assertLeafType(type: mixed): GraphQLLeafType { - if (!isLeafType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL leaf type.`); - } - return type; -} - -/** - * These types may describe the parent context of a selection set. - */ -export type GraphQLCompositeType = - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType; - -export function isCompositeType(type: mixed): boolean %checks { - return isObjectType(type) || isInterfaceType(type) || isUnionType(type); -} - -export function assertCompositeType(type: mixed): GraphQLCompositeType { - if (!isCompositeType(type)) { - throw new Error( - `Expected ${inspect(type)} to be a GraphQL composite type.`, - ); - } - return type; -} - -/** - * These types may describe the parent context of a selection set. - */ -export type GraphQLAbstractType = GraphQLInterfaceType | GraphQLUnionType; - -export function isAbstractType(type: mixed): boolean %checks { - return isInterfaceType(type) || isUnionType(type); -} - -export function assertAbstractType(type: mixed): GraphQLAbstractType { - if (!isAbstractType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL abstract type.`); - } - return type; -} - -/** - * List Type Wrapper - * - * A list is a wrapping type which points to another type. - * Lists are often created within the context of defining the fields of - * an object type. - * - * Example: - * - * const PersonType = new GraphQLObjectType({ - * name: 'Person', - * fields: () => ({ - * parents: { type: new GraphQLList(PersonType) }, - * children: { type: new GraphQLList(PersonType) }, - * }) - * }) - * - */ -export class GraphQLList<+T: GraphQLType> { - +ofType: T; - - constructor(ofType: T) { - devAssert( - isType(ofType), - `Expected ${inspect(ofType)} to be a GraphQL type.`, - ); - - this.ofType = ofType; - } - - toString(): string { - return '[' + String(this.ofType) + ']'; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [Symbol.toStringTag]() { - return 'GraphQLList'; - } -} - -/** - * Non-Null Type Wrapper - * - * A non-null is a wrapping type which points to another type. - * Non-null types enforce that their values are never null and can ensure - * an error is raised if this ever occurs during a request. It is useful for - * fields which you can make a strong guarantee on non-nullability, for example - * usually the id field of a database row will never be null. - * - * Example: - * - * const RowType = new GraphQLObjectType({ - * name: 'Row', - * fields: () => ({ - * id: { type: new GraphQLNonNull(GraphQLString) }, - * }) - * }) - * - * Note: the enforcement of non-nullability occurs within the executor. - */ -export class GraphQLNonNull<+T: GraphQLNullableType> { - +ofType: T; - - constructor(ofType: T) { - devAssert( - isNullableType(ofType), - `Expected ${inspect(ofType)} to be a GraphQL nullable type.`, - ); - - this.ofType = ofType; - } - - toString(): string { - return String(this.ofType) + '!'; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [Symbol.toStringTag]() { - return 'GraphQLNonNull'; - } -} - -/** - * These types wrap and modify other types - */ - -export type GraphQLWrappingType = GraphQLList | GraphQLNonNull; - -export function isWrappingType(type: mixed): boolean %checks { - return isListType(type) || isNonNullType(type); -} - -export function assertWrappingType(type: mixed): GraphQLWrappingType { - if (!isWrappingType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL wrapping type.`); - } - return type; -} - -/** - * These types can all accept null as a value. - */ -export type GraphQLNullableType = - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLInputObjectType - | GraphQLList; - -export function isNullableType(type: mixed): boolean %checks { - return isType(type) && !isNonNullType(type); -} - -export function assertNullableType(type: mixed): GraphQLNullableType { - if (!isNullableType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL nullable type.`); - } - return type; -} - -/* eslint-disable no-redeclare */ -declare function getNullableType(type: void | null): void; -declare function getNullableType(type: T): T; -declare function getNullableType(type: GraphQLNonNull): T; -export function getNullableType(type) { - /* eslint-enable no-redeclare */ - if (type) { - return isNonNullType(type) ? type.ofType : type; - } -} - -/** - * These named types do not include modifiers like List or NonNull. - */ -export type GraphQLNamedType = - | GraphQLScalarType - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLUnionType - | GraphQLEnumType - | GraphQLInputObjectType; - -export function isNamedType(type: mixed): boolean %checks { - return ( - isScalarType(type) || - isObjectType(type) || - isInterfaceType(type) || - isUnionType(type) || - isEnumType(type) || - isInputObjectType(type) - ); -} - -export function assertNamedType(type: mixed): GraphQLNamedType { - if (!isNamedType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL named type.`); - } - return type; -} - -/* eslint-disable no-redeclare */ -declare function getNamedType(type: void | null): void; -declare function getNamedType(type: GraphQLType): GraphQLNamedType; -export function getNamedType(type) { - /* eslint-enable no-redeclare */ - if (type) { - let unwrappedType = type; - while (isWrappingType(unwrappedType)) { - unwrappedType = unwrappedType.ofType; - } - return unwrappedType; - } -} - -/** - * Used while defining GraphQL types to allow for circular references in - * otherwise immutable type definitions. - */ -export type Thunk<+T> = (() => T) | T; - -function resolveThunk<+T>(thunk: Thunk): T { - // $FlowFixMe[incompatible-use] - return typeof thunk === 'function' ? thunk() : thunk; -} - -function undefineIfEmpty(arr: ?$ReadOnlyArray): ?$ReadOnlyArray { - return arr && arr.length > 0 ? arr : undefined; -} - -/** - * Scalar Type Definition - * - * The leaf values of any request and input values to arguments are - * Scalars (or Enums) and are defined with a name and a series of functions - * used to parse input from ast or variables and to ensure validity. - * - * If a type's serialize function does not return a value (i.e. it returns - * `undefined`) then an error will be raised and a `null` value will be returned - * in the response. If the serialize function returns `null`, then no error will - * be included in the response. - * - * Example: - * - * const OddType = new GraphQLScalarType({ - * name: 'Odd', - * serialize(value) { - * if (value % 2 === 1) { - * return value; - * } - * } - * }); - * - */ -export class GraphQLScalarType { - name: string; - description: ?string; - specifiedByUrl: ?string; - serialize: GraphQLScalarSerializer; - parseValue: GraphQLScalarValueParser; - parseLiteral: GraphQLScalarLiteralParser; - extensions: ?ReadOnlyObjMap; - astNode: ?ScalarTypeDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - constructor(config: $ReadOnly>): void { - const parseValue = config.parseValue ?? identityFunc; - this.name = config.name; - this.description = config.description; - this.specifiedByUrl = config.specifiedByUrl; - this.serialize = config.serialize ?? identityFunc; - this.parseValue = parseValue; - this.parseLiteral = - config.parseLiteral ?? - ((node, variables) => parseValue(valueFromASTUntyped(node, variables))); - this.extensions = config.extensions && toObjMap(config.extensions); - this.astNode = config.astNode; - this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); - - devAssert(typeof config.name === 'string', 'Must provide name.'); - - devAssert( - config.specifiedByUrl == null || - typeof config.specifiedByUrl === 'string', - `${this.name} must provide "specifiedByUrl" as a string, ` + - `but got: ${inspect(config.specifiedByUrl)}.`, - ); - - devAssert( - config.serialize == null || typeof config.serialize === 'function', - `${this.name} must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.`, - ); - - if (config.parseLiteral) { - devAssert( - typeof config.parseValue === 'function' && - typeof config.parseLiteral === 'function', - `${this.name} must provide both "parseValue" and "parseLiteral" functions.`, - ); - } - } - - toConfig(): {| - ...GraphQLScalarTypeConfig, - serialize: GraphQLScalarSerializer, - parseValue: GraphQLScalarValueParser, - parseLiteral: GraphQLScalarLiteralParser, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, - |} { - return { - name: this.name, - description: this.description, - specifiedByUrl: this.specifiedByUrl, - serialize: this.serialize, - parseValue: this.parseValue, - parseLiteral: this.parseLiteral, - extensions: this.extensions, - astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [], - }; - } - - toString(): string { - return this.name; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [Symbol.toStringTag]() { - return 'GraphQLScalarType'; - } -} - -export type GraphQLScalarSerializer = ( - outputValue: mixed, -) => ?TExternal; - -export type GraphQLScalarValueParser = ( - inputValue: mixed, -) => ?TInternal; - -export type GraphQLScalarLiteralParser = ( - valueNode: ValueNode, - variables: ?ObjMap, -) => ?TInternal; - -export type GraphQLScalarTypeConfig = {| - name: string, - description?: ?string, - specifiedByUrl?: ?string, - // Serializes an internal value to include in a response. - serialize?: GraphQLScalarSerializer, - // Parses an externally provided value to use as an input. - parseValue?: GraphQLScalarValueParser, - // Parses an externally provided literal value to use as an input. - parseLiteral?: GraphQLScalarLiteralParser, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?ScalarTypeDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, -|}; - -/** - * Object Type Definition - * - * Almost all of the GraphQL types you define will be object types. Object types - * have a name, but most importantly describe their fields. - * - * Example: - * - * const AddressType = new GraphQLObjectType({ - * name: 'Address', - * fields: { - * street: { type: GraphQLString }, - * number: { type: GraphQLInt }, - * formatted: { - * type: GraphQLString, - * resolve(obj) { - * return obj.number + ' ' + obj.street - * } - * } - * } - * }); - * - * When two types need to refer to each other, or a type needs to refer to - * itself in a field, you can use a function expression (aka a closure or a - * thunk) to supply the fields lazily. - * - * Example: - * - * const PersonType = new GraphQLObjectType({ - * name: 'Person', - * fields: () => ({ - * name: { type: GraphQLString }, - * bestFriend: { type: PersonType }, - * }) - * }); - * - */ -export class GraphQLObjectType { - name: string; - description: ?string; - isTypeOf: ?GraphQLIsTypeOfFn; - extensions: ?ReadOnlyObjMap; - astNode: ?ObjectTypeDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - _fields: Thunk>; - _interfaces: Thunk>; - - constructor(config: $ReadOnly>): void { - this.name = config.name; - this.description = config.description; - this.isTypeOf = config.isTypeOf; - this.extensions = config.extensions && toObjMap(config.extensions); - this.astNode = config.astNode; - this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); - - this._fields = defineFieldMap.bind(undefined, config); - this._interfaces = defineInterfaces.bind(undefined, config); - devAssert(typeof config.name === 'string', 'Must provide name.'); - devAssert( - config.isTypeOf == null || typeof config.isTypeOf === 'function', - `${this.name} must provide "isTypeOf" as a function, ` + - `but got: ${inspect(config.isTypeOf)}.`, - ); - } - - getFields(): GraphQLFieldMap { - if (typeof this._fields === 'function') { - this._fields = this._fields(); - } - return this._fields; - } - - getInterfaces(): Array { - if (typeof this._interfaces === 'function') { - this._interfaces = this._interfaces(); - } - return this._interfaces; - } - - toConfig(): {| - ...GraphQLObjectTypeConfig, - interfaces: Array, - fields: GraphQLFieldConfigMap, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, - |} { - return { - name: this.name, - description: this.description, - interfaces: this.getInterfaces(), - fields: fieldsToFieldsConfig(this.getFields()), - isTypeOf: this.isTypeOf, - extensions: this.extensions, - astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes || [], - }; - } - - toString(): string { - return this.name; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [Symbol.toStringTag]() { - return 'GraphQLObjectType'; - } -} - -function defineInterfaces( - config: $ReadOnly< - | GraphQLObjectTypeConfig - | GraphQLInterfaceTypeConfig, - >, -): Array { - const interfaces = resolveThunk(config.interfaces) ?? []; - devAssert( - Array.isArray(interfaces), - `${config.name} interfaces must be an Array or a function which returns an Array.`, - ); - return interfaces; -} - -function defineFieldMap( - config: $ReadOnly< - | GraphQLObjectTypeConfig - | GraphQLInterfaceTypeConfig, - >, -): GraphQLFieldMap { - const fieldMap = resolveThunk(config.fields); - devAssert( - isPlainObj(fieldMap), - `${config.name} fields must be an object with field names as keys or a function which returns such an object.`, - ); - - return mapValue(fieldMap, (fieldConfig, fieldName) => { - devAssert( - isPlainObj(fieldConfig), - `${config.name}.${fieldName} field config must be an object.`, - ); - devAssert( - fieldConfig.resolve == null || typeof fieldConfig.resolve === 'function', - `${config.name}.${fieldName} field resolver must be a function if ` + - `provided, but got: ${inspect(fieldConfig.resolve)}.`, - ); - - const argsConfig = fieldConfig.args ?? {}; - devAssert( - isPlainObj(argsConfig), - `${config.name}.${fieldName} args must be an object with argument names as keys.`, - ); - - const args = objectEntries(argsConfig).map(([argName, argConfig]) => ({ - name: argName, - description: argConfig.description, - type: argConfig.type, - defaultValue: argConfig.defaultValue, - deprecationReason: argConfig.deprecationReason, - extensions: argConfig.extensions && toObjMap(argConfig.extensions), - astNode: argConfig.astNode, - })); - - return { - name: fieldName, - description: fieldConfig.description, - type: fieldConfig.type, - args, - resolve: fieldConfig.resolve, - subscribe: fieldConfig.subscribe, - deprecationReason: fieldConfig.deprecationReason, - extensions: fieldConfig.extensions && toObjMap(fieldConfig.extensions), - astNode: fieldConfig.astNode, - }; - }); -} - -function isPlainObj(obj: mixed): boolean { - return isObjectLike(obj) && !Array.isArray(obj); -} - -function fieldsToFieldsConfig( - fields: GraphQLFieldMap, -): GraphQLFieldConfigMap { - return mapValue(fields, (field) => ({ - description: field.description, - type: field.type, - args: argsToArgsConfig(field.args), - resolve: field.resolve, - subscribe: field.subscribe, - deprecationReason: field.deprecationReason, - extensions: field.extensions, - astNode: field.astNode, - })); -} - -/** - * @internal - */ -export function argsToArgsConfig( - args: $ReadOnlyArray, -): GraphQLFieldConfigArgumentMap { - return keyValMap( - args, - (arg) => arg.name, - (arg) => ({ - description: arg.description, - type: arg.type, - defaultValue: arg.defaultValue, - deprecationReason: arg.deprecationReason, - extensions: arg.extensions, - astNode: arg.astNode, - }), - ); -} - -export type GraphQLObjectTypeConfig = {| - name: string, - description?: ?string, - interfaces?: Thunk>, - fields: Thunk>, - isTypeOf?: ?GraphQLIsTypeOfFn, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?ObjectTypeDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, -|}; - -/** - * Note: returning GraphQLObjectType is deprecated and will be removed in v16.0.0 - */ -export type GraphQLTypeResolver = ( - value: TSource, - context: TContext, - info: GraphQLResolveInfo, - abstractType: GraphQLAbstractType, -) => PromiseOrValue; - -export type GraphQLIsTypeOfFn = ( - source: TSource, - context: TContext, - info: GraphQLResolveInfo, -) => PromiseOrValue; - -export type GraphQLFieldResolver< - TSource, - TContext, - TArgs = { [argument: string]: any, ... }, -> = ( - source: TSource, - args: TArgs, - context: TContext, - info: GraphQLResolveInfo, -) => mixed; - -export type GraphQLResolveInfo = {| - +fieldName: string, - +fieldNodes: $ReadOnlyArray, - +returnType: GraphQLOutputType, - +parentType: GraphQLObjectType, - +path: Path, - +schema: GraphQLSchema, - +fragments: ObjMap, - +rootValue: mixed, - +operation: OperationDefinitionNode, - +variableValues: { [variable: string]: mixed, ... }, -|}; - -export type GraphQLFieldConfig< - TSource, - TContext, - TArgs = { [argument: string]: any, ... }, -> = {| - description?: ?string, - type: GraphQLOutputType, - args?: GraphQLFieldConfigArgumentMap, - resolve?: GraphQLFieldResolver, - subscribe?: GraphQLFieldResolver, - deprecationReason?: ?string, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?FieldDefinitionNode, -|}; - -export type GraphQLFieldConfigArgumentMap = ObjMap; - -export type GraphQLArgumentConfig = {| - description?: ?string, - type: GraphQLInputType, - defaultValue?: mixed, - extensions?: ?ReadOnlyObjMapLike, - deprecationReason?: ?string, - astNode?: ?InputValueDefinitionNode, -|}; - -export type GraphQLFieldConfigMap = ObjMap< - GraphQLFieldConfig, ->; - -export type GraphQLField< - TSource, - TContext, - TArgs = { [argument: string]: any, ... }, -> = {| - name: string, - description: ?string, - type: GraphQLOutputType, - args: Array, - resolve?: GraphQLFieldResolver, - subscribe?: GraphQLFieldResolver, - deprecationReason: ?string, - extensions: ?ReadOnlyObjMap, - astNode: ?FieldDefinitionNode, -|}; - -export type GraphQLArgument = {| - name: string, - description: ?string, - type: GraphQLInputType, - defaultValue: mixed, - deprecationReason: ?string, - extensions: ?ReadOnlyObjMap, - astNode: ?InputValueDefinitionNode, -|}; - -export function isRequiredArgument(arg: GraphQLArgument): boolean %checks { - return isNonNullType(arg.type) && arg.defaultValue === undefined; -} - -export type GraphQLFieldMap = ObjMap< - GraphQLField, ->; - -/** - * Interface Type Definition - * - * When a field can return one of a heterogeneous set of types, a Interface type - * is used to describe what types are possible, what fields are in common across - * all types, as well as a function to determine which type is actually used - * when the field is resolved. - * - * Example: - * - * const EntityType = new GraphQLInterfaceType({ - * name: 'Entity', - * fields: { - * name: { type: GraphQLString } - * } - * }); - * - */ -export class GraphQLInterfaceType { - name: string; - description: ?string; - resolveType: ?GraphQLTypeResolver; - extensions: ?ReadOnlyObjMap; - astNode: ?InterfaceTypeDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - _fields: Thunk>; - _interfaces: Thunk>; - - constructor(config: $ReadOnly>): void { - this.name = config.name; - this.description = config.description; - this.resolveType = config.resolveType; - this.extensions = config.extensions && toObjMap(config.extensions); - this.astNode = config.astNode; - this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); - - this._fields = defineFieldMap.bind(undefined, config); - this._interfaces = defineInterfaces.bind(undefined, config); - devAssert(typeof config.name === 'string', 'Must provide name.'); - devAssert( - config.resolveType == null || typeof config.resolveType === 'function', - `${this.name} must provide "resolveType" as a function, ` + - `but got: ${inspect(config.resolveType)}.`, - ); - } - - getFields(): GraphQLFieldMap { - if (typeof this._fields === 'function') { - this._fields = this._fields(); - } - return this._fields; - } - - getInterfaces(): Array { - if (typeof this._interfaces === 'function') { - this._interfaces = this._interfaces(); - } - return this._interfaces; - } - - toConfig(): {| - ...GraphQLInterfaceTypeConfig, - interfaces: Array, - fields: GraphQLFieldConfigMap, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, - |} { - return { - name: this.name, - description: this.description, - interfaces: this.getInterfaces(), - fields: fieldsToFieldsConfig(this.getFields()), - resolveType: this.resolveType, - extensions: this.extensions, - astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [], - }; - } - - toString(): string { - return this.name; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [Symbol.toStringTag]() { - return 'GraphQLInterfaceType'; - } -} - -export type GraphQLInterfaceTypeConfig = {| - name: string, - description?: ?string, - interfaces?: Thunk>, - fields: Thunk>, - /** - * Optionally provide a custom type resolver function. If one is not provided, - * the default implementation will call `isTypeOf` on each implementing - * Object type. - */ - resolveType?: ?GraphQLTypeResolver, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?InterfaceTypeDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, -|}; - -/** - * Union Type Definition - * - * When a field can return one of a heterogeneous set of types, a Union type - * is used to describe what types are possible as well as providing a function - * to determine which type is actually used when the field is resolved. - * - * Example: - * - * const PetType = new GraphQLUnionType({ - * name: 'Pet', - * types: [ DogType, CatType ], - * resolveType(value) { - * if (value instanceof Dog) { - * return DogType; - * } - * if (value instanceof Cat) { - * return CatType; - * } - * } - * }); - * - */ -export class GraphQLUnionType { - name: string; - description: ?string; - resolveType: ?GraphQLTypeResolver; - extensions: ?ReadOnlyObjMap; - astNode: ?UnionTypeDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - _types: Thunk>; - - constructor(config: $ReadOnly>): void { - this.name = config.name; - this.description = config.description; - this.resolveType = config.resolveType; - this.extensions = config.extensions && toObjMap(config.extensions); - this.astNode = config.astNode; - this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); - - this._types = defineTypes.bind(undefined, config); - devAssert(typeof config.name === 'string', 'Must provide name.'); - devAssert( - config.resolveType == null || typeof config.resolveType === 'function', - `${this.name} must provide "resolveType" as a function, ` + - `but got: ${inspect(config.resolveType)}.`, - ); - } - - getTypes(): Array { - if (typeof this._types === 'function') { - this._types = this._types(); - } - return this._types; - } - - toConfig(): {| - ...GraphQLUnionTypeConfig, - types: Array, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, - |} { - return { - name: this.name, - description: this.description, - types: this.getTypes(), - resolveType: this.resolveType, - extensions: this.extensions, - astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [], - }; - } - - toString(): string { - return this.name; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [Symbol.toStringTag]() { - return 'GraphQLUnionType'; - } -} - -function defineTypes( - config: $ReadOnly>, -): Array { - const types = resolveThunk(config.types); - devAssert( - Array.isArray(types), - `Must provide Array of types or a function which returns such an array for Union ${config.name}.`, - ); - return types; -} - -export type GraphQLUnionTypeConfig = {| - name: string, - description?: ?string, - types: Thunk>, - /** - * Optionally provide a custom type resolver function. If one is not provided, - * the default implementation will call `isTypeOf` on each implementing - * Object type. - */ - resolveType?: ?GraphQLTypeResolver, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?UnionTypeDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, -|}; - -/** - * Enum Type Definition - * - * Some leaf values of requests and input values are Enums. GraphQL serializes - * Enum values as strings, however internally Enums can be represented by any - * kind of type, often integers. - * - * Example: - * - * const RGBType = new GraphQLEnumType({ - * name: 'RGB', - * values: { - * RED: { value: 0 }, - * GREEN: { value: 1 }, - * BLUE: { value: 2 } - * } - * }); - * - * Note: If a value is not provided in a definition, the name of the enum value - * will be used as its internal value. - */ -export class GraphQLEnumType /* */ { - name: string; - description: ?string; - extensions: ?ReadOnlyObjMap; - astNode: ?EnumTypeDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - _values: Array */>; - _valueLookup: Map; - _nameLookup: ObjMap; - - constructor(config: $ReadOnly */>): void { - this.name = config.name; - this.description = config.description; - this.extensions = config.extensions && toObjMap(config.extensions); - this.astNode = config.astNode; - this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); - - this._values = defineEnumValues(this.name, config.values); - this._valueLookup = new Map( - this._values.map((enumValue) => [enumValue.value, enumValue]), - ); - this._nameLookup = keyMap(this._values, (value) => value.name); - - devAssert(typeof config.name === 'string', 'Must provide name.'); - } - - getValues(): Array */> { - return this._values; - } - - getValue(name: string): ?GraphQLEnumValue { - return this._nameLookup[name]; - } - - serialize(outputValue: mixed /* T */): ?string { - const enumValue = this._valueLookup.get(outputValue); - if (enumValue === undefined) { - throw new GraphQLError( - `Enum "${this.name}" cannot represent value: ${inspect(outputValue)}`, - ); - } - return enumValue.name; - } - - parseValue(inputValue: mixed): ?any /* T */ { - if (typeof inputValue !== 'string') { - const valueStr = inspect(inputValue); - throw new GraphQLError( - `Enum "${this.name}" cannot represent non-string value: ${valueStr}.` + - didYouMeanEnumValue(this, valueStr), - ); - } - - const enumValue = this.getValue(inputValue); - if (enumValue == null) { - throw new GraphQLError( - `Value "${inputValue}" does not exist in "${this.name}" enum.` + - didYouMeanEnumValue(this, inputValue), - ); - } - return enumValue.value; - } - - parseLiteral(valueNode: ValueNode, _variables: ?ObjMap): ?any /* T */ { - // Note: variables will be resolved to a value before calling this function. - if (valueNode.kind !== Kind.ENUM) { - const valueStr = print(valueNode); - throw new GraphQLError( - `Enum "${this.name}" cannot represent non-enum value: ${valueStr}.` + - didYouMeanEnumValue(this, valueStr), - valueNode, - ); - } - - const enumValue = this.getValue(valueNode.value); - if (enumValue == null) { - const valueStr = print(valueNode); - throw new GraphQLError( - `Value "${valueStr}" does not exist in "${this.name}" enum.` + - didYouMeanEnumValue(this, valueStr), - valueNode, - ); - } - return enumValue.value; - } - - toConfig(): {| - ...GraphQLEnumTypeConfig, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, - |} { - const values = keyValMap( - this.getValues(), - (value) => value.name, - (value) => ({ - description: value.description, - value: value.value, - deprecationReason: value.deprecationReason, - extensions: value.extensions, - astNode: value.astNode, - }), - ); - - return { - name: this.name, - description: this.description, - values, - extensions: this.extensions, - astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [], - }; - } - - toString(): string { - return this.name; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [Symbol.toStringTag]() { - return 'GraphQLEnumType'; - } -} - -function didYouMeanEnumValue( - enumType: GraphQLEnumType, - unknownValueStr: string, -): string { - const allNames = enumType.getValues().map((value) => value.name); - const suggestedValues = suggestionList(unknownValueStr, allNames); - - return didYouMean('the enum value', suggestedValues); -} - -function defineEnumValues( - typeName: string, - valueMap: GraphQLEnumValueConfigMap /* */, -): Array */> { - devAssert( - isPlainObj(valueMap), - `${typeName} values must be an object with value names as keys.`, - ); - return objectEntries(valueMap).map(([valueName, valueConfig]) => { - devAssert( - isPlainObj(valueConfig), - `${typeName}.${valueName} must refer to an object with a "value" key ` + - `representing an internal value but got: ${inspect(valueConfig)}.`, - ); - return { - name: valueName, - description: valueConfig.description, - value: valueConfig.value !== undefined ? valueConfig.value : valueName, - deprecationReason: valueConfig.deprecationReason, - extensions: valueConfig.extensions && toObjMap(valueConfig.extensions), - astNode: valueConfig.astNode, - }; - }); -} - -export type GraphQLEnumTypeConfig /* */ = {| - name: string, - description?: ?string, - values: GraphQLEnumValueConfigMap /* */, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?EnumTypeDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, -|}; - -export type GraphQLEnumValueConfigMap /* */ = ObjMap */>; - -export type GraphQLEnumValueConfig /* */ = {| - description?: ?string, - value?: any /* T */, - deprecationReason?: ?string, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?EnumValueDefinitionNode, -|}; - -export type GraphQLEnumValue /* */ = {| - name: string, - description: ?string, - value: any /* T */, - deprecationReason: ?string, - extensions: ?ReadOnlyObjMap, - astNode: ?EnumValueDefinitionNode, -|}; - -/** - * Input Object Type Definition - * - * An input object defines a structured collection of fields which may be - * supplied to a field argument. - * - * Using `NonNull` will ensure that a value must be provided by the query - * - * Example: - * - * const GeoPoint = new GraphQLInputObjectType({ - * name: 'GeoPoint', - * fields: { - * lat: { type: new GraphQLNonNull(GraphQLFloat) }, - * lon: { type: new GraphQLNonNull(GraphQLFloat) }, - * alt: { type: GraphQLFloat, defaultValue: 0 }, - * } - * }); - * - */ -export class GraphQLInputObjectType { - name: string; - description: ?string; - extensions: ?ReadOnlyObjMap; - astNode: ?InputObjectTypeDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - _fields: Thunk; - - constructor(config: $ReadOnly): void { - this.name = config.name; - this.description = config.description; - this.extensions = config.extensions && toObjMap(config.extensions); - this.astNode = config.astNode; - this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); - - this._fields = defineInputFieldMap.bind(undefined, config); - devAssert(typeof config.name === 'string', 'Must provide name.'); - } - - getFields(): GraphQLInputFieldMap { - if (typeof this._fields === 'function') { - this._fields = this._fields(); - } - return this._fields; - } - - toConfig(): {| - ...GraphQLInputObjectTypeConfig, - fields: GraphQLInputFieldConfigMap, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, - |} { - const fields = mapValue(this.getFields(), (field) => ({ - description: field.description, - type: field.type, - defaultValue: field.defaultValue, - extensions: field.extensions, - astNode: field.astNode, - })); - - return { - name: this.name, - description: this.description, - fields, - extensions: this.extensions, - astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [], - }; - } - - toString(): string { - return this.name; - } - - toJSON(): string { - return this.toString(); - } - - // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet - get [Symbol.toStringTag]() { - return 'GraphQLInputObjectType'; - } -} - -function defineInputFieldMap( - config: $ReadOnly, -): GraphQLInputFieldMap { - const fieldMap = resolveThunk(config.fields); - devAssert( - isPlainObj(fieldMap), - `${config.name} fields must be an object with field names as keys or a function which returns such an object.`, - ); - return mapValue(fieldMap, (fieldConfig, fieldName) => { - devAssert( - !('resolve' in fieldConfig), - `${config.name}.${fieldName} field has a resolve property, but Input Types cannot define resolvers.`, - ); - - return { - name: fieldName, - description: fieldConfig.description, - type: fieldConfig.type, - defaultValue: fieldConfig.defaultValue, - deprecationReason: fieldConfig.deprecationReason, - extensions: fieldConfig.extensions && toObjMap(fieldConfig.extensions), - astNode: fieldConfig.astNode, - }; - }); -} - -export type GraphQLInputObjectTypeConfig = {| - name: string, - description?: ?string, - fields: Thunk, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?InputObjectTypeDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, -|}; - -export type GraphQLInputFieldConfig = {| - description?: ?string, - type: GraphQLInputType, - defaultValue?: mixed, - deprecationReason?: ?string, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?InputValueDefinitionNode, -|}; - -export type GraphQLInputFieldConfigMap = ObjMap; - -export type GraphQLInputField = {| - name: string, - description: ?string, - type: GraphQLInputType, - defaultValue: mixed, - deprecationReason: ?string, - extensions: ?ReadOnlyObjMap, - astNode: ?InputValueDefinitionNode, -|}; - -export function isRequiredInputField( - field: GraphQLInputField, -): boolean %checks { - return isNonNullType(field.type) && field.defaultValue === undefined; -} - -export type GraphQLInputFieldMap = ObjMap; diff --git a/src/type/definition.ts b/src/type/definition.ts new file mode 100644 index 00000000000..ccafef7723a --- /dev/null +++ b/src/type/definition.ts @@ -0,0 +1,1355 @@ +import { $ReadOnly } from "utility-types"; +import objectEntries from "../polyfills/objectEntries"; + +import { Path } from "../jsutils/Path"; +import { PromiseOrValue } from "../jsutils/PromiseOrValue"; +import { ObjMap, ReadOnlyObjMap, ReadOnlyObjMapLike } from "../jsutils/ObjMap"; +import inspect from "../jsutils/inspect"; +import keyMap from "../jsutils/keyMap"; +import mapValue from "../jsutils/mapValue"; +import toObjMap from "../jsutils/toObjMap"; +import devAssert from "../jsutils/devAssert"; +import keyValMap from "../jsutils/keyValMap"; +import instanceOf from "../jsutils/instanceOf"; +import didYouMean from "../jsutils/didYouMean"; +import isObjectLike from "../jsutils/isObjectLike"; +import identityFunc from "../jsutils/identityFunc"; +import suggestionList from "../jsutils/suggestionList"; + +import { GraphQLError } from "../error/GraphQLError"; + +import { Kind } from "../language/kinds"; +import { print } from "../language/printer"; +import { ScalarTypeDefinitionNode, ObjectTypeDefinitionNode, FieldDefinitionNode, InputValueDefinitionNode, InterfaceTypeDefinitionNode, UnionTypeDefinitionNode, EnumTypeDefinitionNode, EnumValueDefinitionNode, InputObjectTypeDefinitionNode, ScalarTypeExtensionNode, ObjectTypeExtensionNode, InterfaceTypeExtensionNode, UnionTypeExtensionNode, EnumTypeExtensionNode, InputObjectTypeExtensionNode, OperationDefinitionNode, FieldNode, FragmentDefinitionNode, ValueNode } from "../language/ast"; + +import { valueFromASTUntyped } from "../utilities/valueFromASTUntyped"; + +import { GraphQLSchema } from "./schema"; + +// Predicates & Assertions + +/** + * These are all of the possible kinds of types. + */ +export type GraphQLType = GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLInputObjectType | GraphQLList | GraphQLNonNull; + +export function isType(type: unknown): boolean { + return (isScalarType(type) || isObjectType(type) || isInterfaceType(type) || isUnionType(type) || isEnumType(type) || isInputObjectType(type) || isListType(type) || isNonNullType(type)); +} + +export function assertType(type: unknown): GraphQLType { + if (!isType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL type.`); + } + return type; +} + +/** + * There are predicates for each kind of GraphQL type. + */ +declare function isScalarType(type: unknown): boolean; +// eslint-disable-next-line no-redeclare +export function isScalarType(type) { + return instanceOf(type, GraphQLScalarType); +} + +export function assertScalarType(type: unknown): GraphQLScalarType { + if (!isScalarType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Scalar type.`); + } + return type; +} + +declare function isObjectType(type: unknown): boolean; +// eslint-disable-next-line no-redeclare +export function isObjectType(type) { + return instanceOf(type, GraphQLObjectType); +} + +export function assertObjectType(type: unknown): GraphQLObjectType { + if (!isObjectType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Object type.`); + } + return type; +} + +declare function isInterfaceType(type: unknown): boolean; +// eslint-disable-next-line no-redeclare +export function isInterfaceType(type) { + return instanceOf(type, GraphQLInterfaceType); +} + +export function assertInterfaceType(type: unknown): GraphQLInterfaceType { + if (!isInterfaceType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Interface type.`); + } + return type; +} + +declare function isUnionType(type: unknown): boolean; +// eslint-disable-next-line no-redeclare +export function isUnionType(type) { + return instanceOf(type, GraphQLUnionType); +} + +export function assertUnionType(type: unknown): GraphQLUnionType { + if (!isUnionType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Union type.`); + } + return type; +} + +declare function isEnumType(type: unknown): boolean; +// eslint-disable-next-line no-redeclare +export function isEnumType(type) { + return instanceOf(type, GraphQLEnumType); +} + +export function assertEnumType(type: unknown): GraphQLEnumType { + if (!isEnumType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Enum type.`); + } + return type; +} + +declare function isInputObjectType(type: unknown): boolean; +// eslint-disable-next-line no-redeclare +export function isInputObjectType(type) { + return instanceOf(type, GraphQLInputObjectType); +} + +export function assertInputObjectType(type: unknown): GraphQLInputObjectType { + if (!isInputObjectType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Input Object type.`); + } + return type; +} + +declare function isListType(type: unknown): boolean; +// eslint-disable-next-line no-redeclare +export function isListType(type) { + return instanceOf(type, GraphQLList); +} + +export function assertListType(type: unknown): GraphQLList { + if (!isListType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL List type.`); + } + return type; +} + +declare function isNonNullType(type: unknown): boolean; +// eslint-disable-next-line no-redeclare +export function isNonNullType(type) { + return instanceOf(type, GraphQLNonNull); +} + +export function assertNonNullType(type: unknown): GraphQLNonNull { + if (!isNonNullType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL Non-Null type.`); + } + return type; +} + +/** + * These types may be used as input types for arguments and directives. + */ +export type GraphQLInputType = GraphQLScalarType | GraphQLEnumType | GraphQLInputObjectType | GraphQLList | GraphQLNonNull>; + +export function isInputType(type: unknown): boolean { + return (isScalarType(type) || isEnumType(type) || isInputObjectType(type) || (isWrappingType(type) && isInputType(type.ofType))); +} + +export function assertInputType(type: unknown): GraphQLInputType { + if (!isInputType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL input type.`); + } + return type; +} + +/** + * These types may be used as output types as the result of fields. + */ +export type GraphQLOutputType = GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLList | GraphQLNonNull>; + +export function isOutputType(type: unknown): boolean { + return (isScalarType(type) || isObjectType(type) || isInterfaceType(type) || isUnionType(type) || isEnumType(type) || (isWrappingType(type) && isOutputType(type.ofType))); +} + +export function assertOutputType(type: unknown): GraphQLOutputType { + if (!isOutputType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL output type.`); + } + return type; +} + +/** + * These types may describe types which may be leaf values. + */ +export type GraphQLLeafType = GraphQLScalarType | GraphQLEnumType; + +export function isLeafType(type: unknown): boolean { + return isScalarType(type) || isEnumType(type); +} + +export function assertLeafType(type: unknown): GraphQLLeafType { + if (!isLeafType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL leaf type.`); + } + return type; +} + +/** + * These types may describe the parent context of a selection set. + */ +export type GraphQLCompositeType = GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType; + +export function isCompositeType(type: unknown): boolean { + return isObjectType(type) || isInterfaceType(type) || isUnionType(type); +} + +export function assertCompositeType(type: unknown): GraphQLCompositeType { + if (!isCompositeType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL composite type.`); + } + return type; +} + +/** + * These types may describe the parent context of a selection set. + */ +export type GraphQLAbstractType = GraphQLInterfaceType | GraphQLUnionType; + +export function isAbstractType(type: unknown): boolean { + return isInterfaceType(type) || isUnionType(type); +} + +export function assertAbstractType(type: unknown): GraphQLAbstractType { + if (!isAbstractType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL abstract type.`); + } + return type; +} + +/** + * List Type Wrapper + * + * A list is a wrapping type which points to another type. + * Lists are often created within the context of defining the fields of + * an object type. + * + * Example: + * + * const PersonType = new GraphQLObjectType({ + * name: 'Person', + * fields: () => ({ + * parents: { type: new GraphQLList(PersonType) }, + * children: { type: new GraphQLList(PersonType) }, + * }) + * }) + * + */ +export class GraphQLList { + + +ofType: T; + + constructor(ofType: T) { + devAssert(isType(ofType), `Expected ${inspect(ofType)} to be a GraphQL type.`); + + this.ofType = ofType; + } + + toString(): string { + return '[' + String(this.ofType) + ']'; + } + + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet + get [Symbol.toStringTag]() { + return 'GraphQLList'; + } +} + +/** + * Non-Null Type Wrapper + * + * A non-null is a wrapping type which points to another type. + * Non-null types enforce that their values are never null and can ensure + * an error is raised if this ever occurs during a request. It is useful for + * fields which you can make a strong guarantee on non-nullability, for example + * usually the id field of a database row will never be null. + * + * Example: + * + * const RowType = new GraphQLObjectType({ + * name: 'Row', + * fields: () => ({ + * id: { type: new GraphQLNonNull(GraphQLString) }, + * }) + * }) + * + * Note: the enforcement of non-nullability occurs within the executor. + */ +export class GraphQLNonNull { + + +ofType: T; + + constructor(ofType: T) { + devAssert(isNullableType(ofType), `Expected ${inspect(ofType)} to be a GraphQL nullable type.`); + + this.ofType = ofType; + } + + toString(): string { + return String(this.ofType) + '!'; + } + + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet + get [Symbol.toStringTag]() { + return 'GraphQLNonNull'; + } +} + +/** + * These types wrap and modify other types + */ +export type GraphQLWrappingType = GraphQLList | GraphQLNonNull; + +export function isWrappingType(type: unknown): boolean { + return isListType(type) || isNonNullType(type); +} + +export function assertWrappingType(type: unknown): GraphQLWrappingType { + if (!isWrappingType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL wrapping type.`); + } + return type; +} + +/** + * These types can all accept null as a value. + */ +export type GraphQLNullableType = GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLInputObjectType | GraphQLList; + +export function isNullableType(type: unknown): boolean { + return isType(type) && !isNonNullType(type); +} + +export function assertNullableType(type: unknown): GraphQLNullableType { + if (!isNullableType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL nullable type.`); + } + return type; +} + +/* eslint-disable no-redeclare */ +declare function getNullableType(type: void | null): void; +declare function getNullableType(type: T): T; +declare function getNullableType(type: GraphQLNonNull): T; +export function getNullableType(type) { + /* eslint-enable no-redeclare */ + if (type) { + return isNonNullType(type) ? type.ofType : type; + } +} + +/** + * These named types do not include modifiers like List or NonNull. + */ +export type GraphQLNamedType = GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLInputObjectType; + +export function isNamedType(type: unknown): boolean { + return (isScalarType(type) || isObjectType(type) || isInterfaceType(type) || isUnionType(type) || isEnumType(type) || isInputObjectType(type)); +} + +export function assertNamedType(type: unknown): GraphQLNamedType { + if (!isNamedType(type)) { + throw new Error(`Expected ${inspect(type)} to be a GraphQL named type.`); + } + return type; +} + +/* eslint-disable no-redeclare */ +declare function getNamedType(type: void | null): void; +declare function getNamedType(type: GraphQLType): GraphQLNamedType; +export function getNamedType(type) { + /* eslint-enable no-redeclare */ + if (type) { + let unwrappedType = type; + while (isWrappingType(unwrappedType)) { + unwrappedType = unwrappedType.ofType; + } + return unwrappedType; + } +} + +/** + * Used while defining GraphQL types to allow for circular references in + * otherwise immutable type definitions. + */ +export type Thunk = (() => T) | T; + +function resolveThunk(thunk: Thunk): T { + // $FlowFixMe[incompatible-use] + return typeof thunk === 'function' ? thunk() : thunk; +} + +function undefineIfEmpty(arr: ReadonlyArray | null | undefined): ReadonlyArray | null | undefined { + return arr && arr.length > 0 ? arr : undefined; +} + +/** + * Scalar Type Definition + * + * The leaf values of any request and input values to arguments are + * Scalars (or Enums) and are defined with a name and a series of functions + * used to parse input from ast or variables and to ensure validity. + * + * If a type's serialize function does not return a value (i.e. it returns + * `undefined`) then an error will be raised and a `null` value will be returned + * in the response. If the serialize function returns `null`, then no error will + * be included in the response. + * + * Example: + * + * const OddType = new GraphQLScalarType({ + * name: 'Odd', + * serialize(value) { + * if (value % 2 === 1) { + * return value; + * } + * } + * }); + * + */ +export class GraphQLScalarType { + + name: string; + description: string | null | undefined; + specifiedByUrl: string | null | undefined; + serialize: GraphQLScalarSerializer; + parseValue: GraphQLScalarValueParser; + parseLiteral: GraphQLScalarLiteralParser; + extensions: ReadOnlyObjMap | null | undefined; + astNode: ScalarTypeDefinitionNode | null | undefined; + extensionASTNodes: ReadonlyArray | null | undefined; + + constructor(config: $ReadOnly>): void { + const parseValue = config.parseValue ?? identityFunc; + this.name = config.name; + this.description = config.description; + this.specifiedByUrl = config.specifiedByUrl; + this.serialize = config.serialize ?? identityFunc; + this.parseValue = parseValue; + this.parseLiteral = config.parseLiteral ?? ((node, variables) => parseValue(valueFromASTUntyped(node, variables))); + this.extensions = config.extensions && toObjMap(config.extensions); + this.astNode = config.astNode; + this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); + + devAssert(typeof config.name === 'string', 'Must provide name.'); + + devAssert(config.specifiedByUrl == null || typeof config.specifiedByUrl === 'string', `${this.name} must provide "specifiedByUrl" as a string, ` + `but got: ${inspect(config.specifiedByUrl)}.`); + + devAssert(config.serialize == null || typeof config.serialize === 'function', `${this.name} must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.`); + + if (config.parseLiteral) { + devAssert(typeof config.parseValue === 'function' && typeof config.parseLiteral === 'function', `${this.name} must provide both "parseValue" and "parseLiteral" functions.`); + } + } + + toConfig(): GraphQLScalarTypeConfig & { + serialize: GraphQLScalarSerializer; + parseValue: GraphQLScalarValueParser; + parseLiteral: GraphQLScalarLiteralParser; + extensions: ReadOnlyObjMap | null | undefined; + extensionASTNodes: ReadonlyArray; + } { + return { + name: this.name, + description: this.description, + specifiedByUrl: this.specifiedByUrl, + serialize: this.serialize, + parseValue: this.parseValue, + parseLiteral: this.parseLiteral, + extensions: this.extensions, + astNode: this.astNode, + extensionASTNodes: this.extensionASTNodes ?? [] + }; + } + + toString(): string { + return this.name; + } + + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet + get [Symbol.toStringTag]() { + return 'GraphQLScalarType'; + } +} + +export type GraphQLScalarSerializer = (outputValue: unknown) => TExternal | null | undefined; + +export type GraphQLScalarValueParser = (inputValue: unknown) => TInternal | null | undefined; + +export type GraphQLScalarLiteralParser = (valueNode: ValueNode, variables: ObjMap | null | undefined) => TInternal | null | undefined; + +export type GraphQLScalarTypeConfig = { + name: string; + description?: string | null | undefined; + specifiedByUrl?: string | null | undefined; + // Serializes an internal value to include in a response. + serialize?: GraphQLScalarSerializer; + // Parses an externally provided value to use as an input. + parseValue?: GraphQLScalarValueParser; + // Parses an externally provided literal value to use as an input. + parseLiteral?: GraphQLScalarLiteralParser; + extensions?: ReadOnlyObjMapLike | null | undefined; + astNode?: ScalarTypeDefinitionNode | null | undefined; + extensionASTNodes?: ReadonlyArray | null | undefined; +}; + +/** + * Object Type Definition + * + * Almost all of the GraphQL types you define will be object types. Object types + * have a name, but most importantly describe their fields. + * + * Example: + * + * const AddressType = new GraphQLObjectType({ + * name: 'Address', + * fields: { + * street: { type: GraphQLString }, + * number: { type: GraphQLInt }, + * formatted: { + * type: GraphQLString, + * resolve(obj) { + * return obj.number + ' ' + obj.street + * } + * } + * } + * }); + * + * When two types need to refer to each other, or a type needs to refer to + * itself in a field, you can use a function expression (aka a closure or a + * thunk) to supply the fields lazily. + * + * Example: + * + * const PersonType = new GraphQLObjectType({ + * name: 'Person', + * fields: () => ({ + * name: { type: GraphQLString }, + * bestFriend: { type: PersonType }, + * }) + * }); + * + */ +export class GraphQLObjectType { + + name: string; + description: string | null | undefined; + isTypeOf: GraphQLIsTypeOfFn | null | undefined; + extensions: ReadOnlyObjMap | null | undefined; + astNode: ObjectTypeDefinitionNode | null | undefined; + extensionASTNodes: ReadonlyArray | null | undefined; + + _fields: Thunk>; + _interfaces: Thunk>; + + constructor(config: $ReadOnly>): void { + this.name = config.name; + this.description = config.description; + this.isTypeOf = config.isTypeOf; + this.extensions = config.extensions && toObjMap(config.extensions); + this.astNode = config.astNode; + this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); + + this._fields = defineFieldMap.bind(undefined, config); + this._interfaces = defineInterfaces.bind(undefined, config); + devAssert(typeof config.name === 'string', 'Must provide name.'); + devAssert(config.isTypeOf == null || typeof config.isTypeOf === 'function', `${this.name} must provide "isTypeOf" as a function, ` + `but got: ${inspect(config.isTypeOf)}.`); + } + + getFields(): GraphQLFieldMap { + if (typeof this._fields === 'function') { + this._fields = this._fields(); + } + return this._fields; + } + + getInterfaces(): Array { + if (typeof this._interfaces === 'function') { + this._interfaces = this._interfaces(); + } + return this._interfaces; + } + + toConfig(): GraphQLObjectTypeConfig & { + interfaces: Array; + fields: GraphQLFieldConfigMap; + extensions: ReadOnlyObjMap | null | undefined; + extensionASTNodes: ReadonlyArray; + } { + return { + name: this.name, + description: this.description, + interfaces: this.getInterfaces(), + fields: fieldsToFieldsConfig(this.getFields()), + isTypeOf: this.isTypeOf, + extensions: this.extensions, + astNode: this.astNode, + extensionASTNodes: this.extensionASTNodes || [] + }; + } + + toString(): string { + return this.name; + } + + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet + get [Symbol.toStringTag]() { + return 'GraphQLObjectType'; + } +} + +function defineInterfaces(config: $ReadOnly | GraphQLInterfaceTypeConfig>): Array { + const interfaces = resolveThunk(config.interfaces) ?? []; + devAssert(Array.isArray(interfaces), `${config.name} interfaces must be an Array or a function which returns an Array.`); + return interfaces; +} + +function defineFieldMap(config: $ReadOnly | GraphQLInterfaceTypeConfig>): GraphQLFieldMap { + const fieldMap = resolveThunk(config.fields); + devAssert(isPlainObj(fieldMap), `${config.name} fields must be an object with field names as keys or a function which returns such an object.`); + + return mapValue(fieldMap, (fieldConfig, fieldName) => { + devAssert(isPlainObj(fieldConfig), `${config.name}.${fieldName} field config must be an object.`); + devAssert(fieldConfig.resolve == null || typeof fieldConfig.resolve === 'function', `${config.name}.${fieldName} field resolver must be a function if ` + `provided, but got: ${inspect(fieldConfig.resolve)}.`); + + const argsConfig = fieldConfig.args ?? {}; + devAssert(isPlainObj(argsConfig), `${config.name}.${fieldName} args must be an object with argument names as keys.`); + + const args = objectEntries(argsConfig).map(([argName, argConfig]) => ({ + name: argName, + description: argConfig.description, + type: argConfig.type, + defaultValue: argConfig.defaultValue, + deprecationReason: argConfig.deprecationReason, + extensions: argConfig.extensions && toObjMap(argConfig.extensions), + astNode: argConfig.astNode + })); + + return { + name: fieldName, + description: fieldConfig.description, + type: fieldConfig.type, + args, + resolve: fieldConfig.resolve, + subscribe: fieldConfig.subscribe, + deprecationReason: fieldConfig.deprecationReason, + extensions: fieldConfig.extensions && toObjMap(fieldConfig.extensions), + astNode: fieldConfig.astNode + }; + }); +} + +function isPlainObj(obj: unknown): boolean { + return isObjectLike(obj) && !Array.isArray(obj); +} + +function fieldsToFieldsConfig(fields: GraphQLFieldMap): GraphQLFieldConfigMap { + return mapValue(fields, field => ({ + description: field.description, + type: field.type, + args: argsToArgsConfig(field.args), + resolve: field.resolve, + subscribe: field.subscribe, + deprecationReason: field.deprecationReason, + extensions: field.extensions, + astNode: field.astNode + })); +} + +/** + * @internal + */ +export function argsToArgsConfig(args: ReadonlyArray): GraphQLFieldConfigArgumentMap { + return keyValMap(args, arg => arg.name, arg => ({ + description: arg.description, + type: arg.type, + defaultValue: arg.defaultValue, + deprecationReason: arg.deprecationReason, + extensions: arg.extensions, + astNode: arg.astNode + })); +} + +export type GraphQLObjectTypeConfig = { + name: string; + description?: string | null | undefined; + interfaces?: Thunk | null | undefined>; + fields: Thunk>; + isTypeOf?: GraphQLIsTypeOfFn | null | undefined; + extensions?: ReadOnlyObjMapLike | null | undefined; + astNode?: ObjectTypeDefinitionNode | null | undefined; + extensionASTNodes?: ReadonlyArray | null | undefined; +}; + +/** + * Note: returning GraphQLObjectType is deprecated and will be removed in v16.0.0 + */ +export type GraphQLTypeResolver = (value: TSource, context: TContext, info: GraphQLResolveInfo, abstractType: GraphQLAbstractType) => PromiseOrValue; + +export type GraphQLIsTypeOfFn = (source: TSource, context: TContext, info: GraphQLResolveInfo) => PromiseOrValue; + +export type GraphQLFieldResolver = (source: TSource, args: TArgs, context: TContext, info: GraphQLResolveInfo) => unknown; + +export type GraphQLResolveInfo = { + readonly fieldName: string; + readonly fieldNodes: ReadonlyArray; + readonly returnType: GraphQLOutputType; + readonly parentType: GraphQLObjectType; + readonly path: Path; + readonly schema: GraphQLSchema; + readonly fragments: ObjMap; + readonly rootValue: unknown; + readonly operation: OperationDefinitionNode; + readonly variableValues: { + [variable: string]: unknown; + }; +}; + +export type GraphQLFieldConfig = { + description?: string | null | undefined; + type: GraphQLOutputType; + args?: GraphQLFieldConfigArgumentMap; + resolve?: GraphQLFieldResolver; + subscribe?: GraphQLFieldResolver; + deprecationReason?: string | null | undefined; + extensions?: ReadOnlyObjMapLike | null | undefined; + astNode?: FieldDefinitionNode | null | undefined; +}; + +export type GraphQLFieldConfigArgumentMap = ObjMap; + +export type GraphQLArgumentConfig = { + description?: string | null | undefined; + type: GraphQLInputType; + defaultValue?: unknown; + extensions?: ReadOnlyObjMapLike | null | undefined; + deprecationReason?: string | null | undefined; + astNode?: InputValueDefinitionNode | null | undefined; +}; + +export type GraphQLFieldConfigMap = ObjMap>; + +export type GraphQLField = { + name: string; + description: string | null | undefined; + type: GraphQLOutputType; + args: Array; + resolve?: GraphQLFieldResolver; + subscribe?: GraphQLFieldResolver; + deprecationReason: string | null | undefined; + extensions: ReadOnlyObjMap | null | undefined; + astNode: FieldDefinitionNode | null | undefined; +}; + +export type GraphQLArgument = { + name: string; + description: string | null | undefined; + type: GraphQLInputType; + defaultValue: unknown; + deprecationReason: string | null | undefined; + extensions: ReadOnlyObjMap | null | undefined; + astNode: InputValueDefinitionNode | null | undefined; +}; + +export function isRequiredArgument(arg: GraphQLArgument): boolean { + return isNonNullType(arg.type) && arg.defaultValue === undefined; +} + +export type GraphQLFieldMap = ObjMap>; + +/** + * Interface Type Definition + * + * When a field can return one of a heterogeneous set of types, a Interface type + * is used to describe what types are possible, what fields are in common across + * all types, as well as a function to determine which type is actually used + * when the field is resolved. + * + * Example: + * + * const EntityType = new GraphQLInterfaceType({ + * name: 'Entity', + * fields: { + * name: { type: GraphQLString } + * } + * }); + * + */ +export class GraphQLInterfaceType { + + name: string; + description: string | null | undefined; + resolveType: GraphQLTypeResolver | null | undefined; + extensions: ReadOnlyObjMap | null | undefined; + astNode: InterfaceTypeDefinitionNode | null | undefined; + extensionASTNodes: ReadonlyArray | null | undefined; + + _fields: Thunk>; + _interfaces: Thunk>; + + constructor(config: $ReadOnly>): void { + this.name = config.name; + this.description = config.description; + this.resolveType = config.resolveType; + this.extensions = config.extensions && toObjMap(config.extensions); + this.astNode = config.astNode; + this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); + + this._fields = defineFieldMap.bind(undefined, config); + this._interfaces = defineInterfaces.bind(undefined, config); + devAssert(typeof config.name === 'string', 'Must provide name.'); + devAssert(config.resolveType == null || typeof config.resolveType === 'function', `${this.name} must provide "resolveType" as a function, ` + `but got: ${inspect(config.resolveType)}.`); + } + + getFields(): GraphQLFieldMap { + if (typeof this._fields === 'function') { + this._fields = this._fields(); + } + return this._fields; + } + + getInterfaces(): Array { + if (typeof this._interfaces === 'function') { + this._interfaces = this._interfaces(); + } + return this._interfaces; + } + + toConfig(): GraphQLInterfaceTypeConfig & { + interfaces: Array; + fields: GraphQLFieldConfigMap; + extensions: ReadOnlyObjMap | null | undefined; + extensionASTNodes: ReadonlyArray; + } { + return { + name: this.name, + description: this.description, + interfaces: this.getInterfaces(), + fields: fieldsToFieldsConfig(this.getFields()), + resolveType: this.resolveType, + extensions: this.extensions, + astNode: this.astNode, + extensionASTNodes: this.extensionASTNodes ?? [] + }; + } + + toString(): string { + return this.name; + } + + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet + get [Symbol.toStringTag]() { + return 'GraphQLInterfaceType'; + } +} + +export type GraphQLInterfaceTypeConfig = { + name: string; + description?: string | null | undefined; + interfaces?: Thunk | null | undefined>; + fields: Thunk>; + + /** + * Optionally provide a custom type resolver function. If one is not provided, + * the default implementation will call `isTypeOf` on each implementing + * Object type. + */ + resolveType?: GraphQLTypeResolver | null | undefined; + extensions?: ReadOnlyObjMapLike | null | undefined; + astNode?: InterfaceTypeDefinitionNode | null | undefined; + extensionASTNodes?: ReadonlyArray | null | undefined; +}; + +/** + * Union Type Definition + * + * When a field can return one of a heterogeneous set of types, a Union type + * is used to describe what types are possible as well as providing a function + * to determine which type is actually used when the field is resolved. + * + * Example: + * + * const PetType = new GraphQLUnionType({ + * name: 'Pet', + * types: [ DogType, CatType ], + * resolveType(value) { + * if (value instanceof Dog) { + * return DogType; + * } + * if (value instanceof Cat) { + * return CatType; + * } + * } + * }); + * + */ +export class GraphQLUnionType { + + name: string; + description: string | null | undefined; + resolveType: GraphQLTypeResolver | null | undefined; + extensions: ReadOnlyObjMap | null | undefined; + astNode: UnionTypeDefinitionNode | null | undefined; + extensionASTNodes: ReadonlyArray | null | undefined; + + _types: Thunk>; + + constructor(config: $ReadOnly>): void { + this.name = config.name; + this.description = config.description; + this.resolveType = config.resolveType; + this.extensions = config.extensions && toObjMap(config.extensions); + this.astNode = config.astNode; + this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); + + this._types = defineTypes.bind(undefined, config); + devAssert(typeof config.name === 'string', 'Must provide name.'); + devAssert(config.resolveType == null || typeof config.resolveType === 'function', `${this.name} must provide "resolveType" as a function, ` + `but got: ${inspect(config.resolveType)}.`); + } + + getTypes(): Array { + if (typeof this._types === 'function') { + this._types = this._types(); + } + return this._types; + } + + toConfig(): GraphQLUnionTypeConfig & { + types: Array; + extensions: ReadOnlyObjMap | null | undefined; + extensionASTNodes: ReadonlyArray; + } { + return { + name: this.name, + description: this.description, + types: this.getTypes(), + resolveType: this.resolveType, + extensions: this.extensions, + astNode: this.astNode, + extensionASTNodes: this.extensionASTNodes ?? [] + }; + } + + toString(): string { + return this.name; + } + + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet + get [Symbol.toStringTag]() { + return 'GraphQLUnionType'; + } +} + +function defineTypes(config: $ReadOnly>): Array { + const types = resolveThunk(config.types); + devAssert(Array.isArray(types), `Must provide Array of types or a function which returns such an array for Union ${config.name}.`); + return types; +} + +export type GraphQLUnionTypeConfig = { + name: string; + description?: string | null | undefined; + types: Thunk>; + + /** + * Optionally provide a custom type resolver function. If one is not provided, + * the default implementation will call `isTypeOf` on each implementing + * Object type. + */ + resolveType?: GraphQLTypeResolver | null | undefined; + extensions?: ReadOnlyObjMapLike | null | undefined; + astNode?: UnionTypeDefinitionNode | null | undefined; + extensionASTNodes?: ReadonlyArray | null | undefined; +}; + +/** + * Enum Type Definition + * + * Some leaf values of requests and input values are Enums. GraphQL serializes + * Enum values as strings, however internally Enums can be represented by any + * kind of type, often integers. + * + * Example: + * + * const RGBType = new GraphQLEnumType({ + * name: 'RGB', + * values: { + * RED: { value: 0 }, + * GREEN: { value: 1 }, + * BLUE: { value: 2 } + * } + * }); + * + * Note: If a value is not provided in a definition, the name of the enum value + * will be used as its internal value. + */ +export class GraphQLEnumType +/* */ +{ + + name: string; + description: string | null | undefined; + extensions: ReadOnlyObjMap | null | undefined; + astNode: EnumTypeDefinitionNode | null | undefined; + extensionASTNodes: ReadonlyArray | null | undefined; + + _values: Array */ + >; + _valueLookup: Map; + _nameLookup: ObjMap; + + constructor(config: $ReadOnly */ + >): void { + this.name = config.name; + this.description = config.description; + this.extensions = config.extensions && toObjMap(config.extensions); + this.astNode = config.astNode; + this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); + + this._values = defineEnumValues(this.name, config.values); + this._valueLookup = new Map(this._values.map(enumValue => [enumValue.value, enumValue])); + this._nameLookup = keyMap(this._values, value => value.name); + + devAssert(typeof config.name === 'string', 'Must provide name.'); + } + + getValues(): Array */ + > { + return this._values; + } + + getValue(name: string): GraphQLEnumValue | null | undefined { + return this._nameLookup[name]; + } + + serialize(outputValue: unknown + /* T */ + ): string | null | undefined { + const enumValue = this._valueLookup.get(outputValue); + if (enumValue === undefined) { + throw new GraphQLError(`Enum "${this.name}" cannot represent value: ${inspect(outputValue)}`); + } + return enumValue.name; + } + + parseValue(inputValue: unknown): any | null | undefined + /* T */ + { + if (typeof inputValue !== 'string') { + const valueStr = inspect(inputValue); + throw new GraphQLError(`Enum "${this.name}" cannot represent non-string value: ${valueStr}.` + didYouMeanEnumValue(this, valueStr)); + } + + const enumValue = this.getValue(inputValue); + if (enumValue == null) { + throw new GraphQLError(`Value "${inputValue}" does not exist in "${this.name}" enum.` + didYouMeanEnumValue(this, inputValue)); + } + return enumValue.value; + } + + parseLiteral(valueNode: ValueNode, _variables: ObjMap | null | undefined): any | null | undefined + /* T */ + { + // Note: variables will be resolved to a value before calling this function. + if (valueNode.kind !== Kind.ENUM) { + const valueStr = print(valueNode); + throw new GraphQLError(`Enum "${this.name}" cannot represent non-enum value: ${valueStr}.` + didYouMeanEnumValue(this, valueStr), valueNode); + } + + const enumValue = this.getValue(valueNode.value); + if (enumValue == null) { + const valueStr = print(valueNode); + throw new GraphQLError(`Value "${valueStr}" does not exist in "${this.name}" enum.` + didYouMeanEnumValue(this, valueStr), valueNode); + } + return enumValue.value; + } + + toConfig(): GraphQLEnumTypeConfig & { + extensions: ReadOnlyObjMap | null | undefined; + extensionASTNodes: ReadonlyArray; + } { + const values = keyValMap(this.getValues(), value => value.name, value => ({ + description: value.description, + value: value.value, + deprecationReason: value.deprecationReason, + extensions: value.extensions, + astNode: value.astNode + })); + + return { + name: this.name, + description: this.description, + values, + extensions: this.extensions, + astNode: this.astNode, + extensionASTNodes: this.extensionASTNodes ?? [] + }; + } + + toString(): string { + return this.name; + } + + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet + get [Symbol.toStringTag]() { + return 'GraphQLEnumType'; + } +} + +function didYouMeanEnumValue(enumType: GraphQLEnumType, unknownValueStr: string): string { + const allNames = enumType.getValues().map(value => value.name); + const suggestedValues = suggestionList(unknownValueStr, allNames); + + return didYouMean('the enum value', suggestedValues); +} + +function defineEnumValues(typeName: string, valueMap: GraphQLEnumValueConfigMap +/* */ +): Array */ +> { + devAssert(isPlainObj(valueMap), `${typeName} values must be an object with value names as keys.`); + return objectEntries(valueMap).map(([valueName, valueConfig]) => { + devAssert(isPlainObj(valueConfig), `${typeName}.${valueName} must refer to an object with a "value" key ` + `representing an internal value but got: ${inspect(valueConfig)}.`); + return { + name: valueName, + description: valueConfig.description, + value: valueConfig.value !== undefined ? valueConfig.value : valueName, + deprecationReason: valueConfig.deprecationReason, + extensions: valueConfig.extensions && toObjMap(valueConfig.extensions), + astNode: valueConfig.astNode + }; + }); +} + +export type GraphQLEnumTypeConfig +/* */ += { + name: string; + description?: string | null | undefined; + values: GraphQLEnumValueConfigMap; + /* */ + extensions?: ReadOnlyObjMapLike | null | undefined; + astNode?: EnumTypeDefinitionNode | null | undefined; + extensionASTNodes?: ReadonlyArray | null | undefined; +}; + +export type GraphQLEnumValueConfigMap +/* */ += ObjMap */ +>; +export type GraphQLEnumValueConfig +/* */ += { + description?: string | null | undefined; + value?: any; + /* T */ + deprecationReason?: string | null | undefined; + extensions?: ReadOnlyObjMapLike | null | undefined; + astNode?: EnumValueDefinitionNode | null | undefined; +}; + +export type GraphQLEnumValue +/* */ += { + name: string; + description: string | null | undefined; + value: any; + /* T */ + deprecationReason: string | null | undefined; + extensions: ReadOnlyObjMap | null | undefined; + astNode: EnumValueDefinitionNode | null | undefined; +}; + +/** + * Input Object Type Definition + * + * An input object defines a structured collection of fields which may be + * supplied to a field argument. + * + * Using `NonNull` will ensure that a value must be provided by the query + * + * Example: + * + * const GeoPoint = new GraphQLInputObjectType({ + * name: 'GeoPoint', + * fields: { + * lat: { type: new GraphQLNonNull(GraphQLFloat) }, + * lon: { type: new GraphQLNonNull(GraphQLFloat) }, + * alt: { type: GraphQLFloat, defaultValue: 0 }, + * } + * }); + * + */ +export class GraphQLInputObjectType { + + name: string; + description: string | null | undefined; + extensions: ReadOnlyObjMap | null | undefined; + astNode: InputObjectTypeDefinitionNode | null | undefined; + extensionASTNodes: ReadonlyArray | null | undefined; + + _fields: Thunk; + + constructor(config: $ReadOnly): void { + this.name = config.name; + this.description = config.description; + this.extensions = config.extensions && toObjMap(config.extensions); + this.astNode = config.astNode; + this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); + + this._fields = defineInputFieldMap.bind(undefined, config); + devAssert(typeof config.name === 'string', 'Must provide name.'); + } + + getFields(): GraphQLInputFieldMap { + if (typeof this._fields === 'function') { + this._fields = this._fields(); + } + return this._fields; + } + + toConfig(): GraphQLInputObjectTypeConfig & { + fields: GraphQLInputFieldConfigMap; + extensions: ReadOnlyObjMap | null | undefined; + extensionASTNodes: ReadonlyArray; + } { + const fields = mapValue(this.getFields(), field => ({ + description: field.description, + type: field.type, + defaultValue: field.defaultValue, + extensions: field.extensions, + astNode: field.astNode + })); + + return { + name: this.name, + description: this.description, + fields, + extensions: this.extensions, + astNode: this.astNode, + extensionASTNodes: this.extensionASTNodes ?? [] + }; + } + + toString(): string { + return this.name; + } + + toJSON(): string { + return this.toString(); + } + + // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet + get [Symbol.toStringTag]() { + return 'GraphQLInputObjectType'; + } +} + +function defineInputFieldMap(config: $ReadOnly): GraphQLInputFieldMap { + const fieldMap = resolveThunk(config.fields); + devAssert(isPlainObj(fieldMap), `${config.name} fields must be an object with field names as keys or a function which returns such an object.`); + return mapValue(fieldMap, (fieldConfig, fieldName) => { + devAssert(!('resolve' in fieldConfig), `${config.name}.${fieldName} field has a resolve property, but Input Types cannot define resolvers.`); + + return { + name: fieldName, + description: fieldConfig.description, + type: fieldConfig.type, + defaultValue: fieldConfig.defaultValue, + deprecationReason: fieldConfig.deprecationReason, + extensions: fieldConfig.extensions && toObjMap(fieldConfig.extensions), + astNode: fieldConfig.astNode + }; + }); +} + +export type GraphQLInputObjectTypeConfig = { + name: string; + description?: string | null | undefined; + fields: Thunk; + extensions?: ReadOnlyObjMapLike | null | undefined; + astNode?: InputObjectTypeDefinitionNode | null | undefined; + extensionASTNodes?: ReadonlyArray | null | undefined; +}; + +export type GraphQLInputFieldConfig = { + description?: string | null | undefined; + type: GraphQLInputType; + defaultValue?: unknown; + deprecationReason?: string | null | undefined; + extensions?: ReadOnlyObjMapLike | null | undefined; + astNode?: InputValueDefinitionNode | null | undefined; +}; + +export type GraphQLInputFieldConfigMap = ObjMap; + +export type GraphQLInputField = { + name: string; + description: string | null | undefined; + type: GraphQLInputType; + defaultValue: unknown; + deprecationReason: string | null | undefined; + extensions: ReadOnlyObjMap | null | undefined; + astNode: InputValueDefinitionNode | null | undefined; +}; + +export function isRequiredInputField(field: GraphQLInputField): boolean { + return isNonNullType(field.type) && field.defaultValue === undefined; +} + +export type GraphQLInputFieldMap = ObjMap; \ No newline at end of file diff --git a/src/type/directives.js b/src/type/directives.ts similarity index 81% rename from src/type/directives.js rename to src/type/directives.ts index 83f21864b2a..1fa1d5ba1fd 100644 --- a/src/type/directives.js +++ b/src/type/directives.ts @@ -1,35 +1,31 @@ +import { $ReadOnly } from 'utility-types'; import objectEntries from '../polyfills/objectEntries'; -import type { ReadOnlyObjMap, ReadOnlyObjMapLike } from '../jsutils/ObjMap'; +import { ReadOnlyObjMap, ReadOnlyObjMapLike } from '../jsutils/ObjMap'; import inspect from '../jsutils/inspect'; import toObjMap from '../jsutils/toObjMap'; import devAssert from '../jsutils/devAssert'; import instanceOf from '../jsutils/instanceOf'; import isObjectLike from '../jsutils/isObjectLike'; -import type { DirectiveDefinitionNode } from '../language/ast'; -import type { DirectiveLocationEnum } from '../language/directiveLocation'; +import { DirectiveDefinitionNode } from '../language/ast'; +import { DirectiveLocationEnum } from '../language/directiveLocation'; import { DirectiveLocation } from '../language/directiveLocation'; -import type { - GraphQLArgument, - GraphQLFieldConfigArgumentMap, -} from './definition'; +import { GraphQLArgument, GraphQLFieldConfigArgumentMap } from './definition'; import { GraphQLString, GraphQLBoolean } from './scalars'; import { argsToArgsConfig, GraphQLNonNull } from './definition'; /** * Test if the given value is a GraphQL directive. */ -declare function isDirective( - directive: mixed, -): boolean %checks(directive instanceof GraphQLDirective); +declare function isDirective(directive: unknown): boolean; // eslint-disable-next-line no-redeclare export function isDirective(directive) { return instanceOf(directive, GraphQLDirective); } -export function assertDirective(directive: mixed): GraphQLDirective { +export function assertDirective(directive: unknown): GraphQLDirective { if (!isDirective(directive)) { throw new Error( `Expected ${inspect(directive)} to be a GraphQL directive.`, @@ -44,12 +40,12 @@ export function assertDirective(directive: mixed): GraphQLDirective { */ export class GraphQLDirective { name: string; - description: ?string; + description: string | null | undefined; locations: Array; args: Array; isRepeatable: boolean; - extensions: ?ReadOnlyObjMap; - astNode: ?DirectiveDefinitionNode; + extensions: ReadOnlyObjMap | null | undefined; + astNode: DirectiveDefinitionNode | null | undefined; constructor(config: $ReadOnly): void { this.name = config.name; @@ -82,12 +78,11 @@ export class GraphQLDirective { })); } - toConfig(): {| - ...GraphQLDirectiveConfig, - args: GraphQLFieldConfigArgumentMap, - isRepeatable: boolean, - extensions: ?ReadOnlyObjMap, - |} { + toConfig(): GraphQLDirectiveConfig & { + args: GraphQLFieldConfigArgumentMap; + isRepeatable: boolean; + extensions: ReadOnlyObjMap | null | undefined; + } { return { name: this.name, description: this.description, @@ -113,15 +108,15 @@ export class GraphQLDirective { } } -export type GraphQLDirectiveConfig = {| - name: string, - description?: ?string, - locations: Array, - args?: ?GraphQLFieldConfigArgumentMap, - isRepeatable?: ?boolean, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?DirectiveDefinitionNode, -|}; +export type GraphQLDirectiveConfig = { + name: string; + description?: string | null | undefined; + locations: Array; + args?: GraphQLFieldConfigArgumentMap | null | undefined; + isRepeatable?: boolean | null | undefined; + extensions?: ReadOnlyObjMapLike | null | undefined; + astNode?: DirectiveDefinitionNode | null | undefined; +}; /** * Used to conditionally include fields or fragments. @@ -215,8 +210,6 @@ export const specifiedDirectives = Object.freeze([ GraphQLSpecifiedByDirective, ]); -export function isSpecifiedDirective( - directive: GraphQLDirective, -): boolean %checks { +export function isSpecifiedDirective(directive: GraphQLDirective): boolean { return specifiedDirectives.some(({ name }) => name === directive.name); } diff --git a/src/type/index.js b/src/type/index.ts similarity index 75% rename from src/type/index.js rename to src/type/index.ts index 811d50247ac..2d18cd9f8db 100644 --- a/src/type/index.js +++ b/src/type/index.ts @@ -1,14 +1,12 @@ -export type { Path as ResponsePath } from '../jsutils/Path'; +export { Path as ResponsePath } from '../jsutils/Path'; export { // Predicate - isSchema, - // Assertion - assertSchema, - // GraphQL Schema definition + isSchema, // Assertion + assertSchema, // GraphQL Schema definition GraphQLSchema, } from './schema'; -export type { GraphQLSchemaConfig } from './schema'; +export { GraphQLSchemaConfig } from './schema'; export { // Predicates @@ -30,8 +28,7 @@ export { isNullableType, isNamedType, isRequiredArgument, - isRequiredInputField, - // Assertions + isRequiredInputField, // Assertions assertType, assertScalarType, assertObjectType, @@ -48,47 +45,39 @@ export { assertAbstractType, assertWrappingType, assertNullableType, - assertNamedType, - // Un-modifiers + assertNamedType, // Un-modifiers getNullableType, - getNamedType, - // Definitions + getNamedType, // Definitions GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, - GraphQLInputObjectType, - // Type Wrappers + GraphQLInputObjectType, // Type Wrappers GraphQLList, GraphQLNonNull, } from './definition'; export { // Predicate - isDirective, - // Assertion - assertDirective, - // Directives Definition - GraphQLDirective, - // Built-in Directives defined by the Spec + isDirective, // Assertion + assertDirective, // Directives Definition + GraphQLDirective, // Built-in Directives defined by the Spec isSpecifiedDirective, specifiedDirectives, GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, - GraphQLSpecifiedByDirective, - // Constant Deprecation Reason + GraphQLSpecifiedByDirective, // Constant Deprecation Reason DEFAULT_DEPRECATION_REASON, } from './directives'; -export type { GraphQLDirectiveConfig } from './directives'; +export { GraphQLDirectiveConfig } from './directives'; // Common built-in scalar instances. export { // Predicate - isSpecifiedScalarType, - // Standard GraphQL Scalars + isSpecifiedScalarType, // Standard GraphQL Scalars specifiedScalarTypes, GraphQLInt, GraphQLFloat, @@ -99,8 +88,7 @@ export { export { // Predicate - isIntrospectionType, - // GraphQL Types for introspection. + isIntrospectionType, // GraphQL Types for introspection. introspectionTypes, __Schema, __Directive, @@ -109,16 +97,14 @@ export { __Field, __InputValue, __EnumValue, - __TypeKind, - // "Enum" of Type Kinds - TypeKind, - // Meta-field definitions. + __TypeKind, // "Enum" of Type Kinds + TypeKind, // Meta-field definitions. SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, } from './introspection'; -export type { +export { GraphQLType, GraphQLInputType, GraphQLOutputType, diff --git a/src/type/introspection.js b/src/type/introspection.ts similarity index 95% rename from src/type/introspection.js rename to src/type/introspection.ts index 4963bd96746..9e65a97e8d6 100644 --- a/src/type/introspection.js +++ b/src/type/introspection.ts @@ -7,9 +7,9 @@ import { print } from '../language/printer'; import { DirectiveLocation } from '../language/directiveLocation'; import { astFromValue } from '../utilities/astFromValue'; -import type { GraphQLSchema } from './schema'; -import type { GraphQLDirective } from './directives'; -import type { +import { GraphQLSchema } from './schema'; +import { GraphQLDirective } from './directives'; +import { GraphQLType, GraphQLNamedType, GraphQLInputField, @@ -75,7 +75,7 @@ export const __Schema = new GraphQLObjectType({ ), resolve: (schema) => schema.getDirectives(), }, - }: GraphQLFieldConfigMap), + } as GraphQLFieldConfigMap), }); export const __Directive = new GraphQLObjectType({ @@ -108,7 +108,7 @@ export const __Directive = new GraphQLObjectType({ ), resolve: (directive) => directive.args, }, - }: GraphQLFieldConfigMap), + } as GraphQLFieldConfigMap), }); export const __DirectiveLocation = new GraphQLEnumType({ @@ -231,7 +231,7 @@ export const __Type = new GraphQLObjectType({ } // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false, `Unexpected type: "${inspect((type: empty))}".`); + invariant(false, `Unexpected type: "${inspect(type as never)}".`); }, }, name: { @@ -314,7 +314,7 @@ export const __Type = new GraphQLObjectType({ resolve: (type) => type.ofType !== undefined ? type.ofType : undefined, }, - }: GraphQLFieldConfigMap), + } as GraphQLFieldConfigMap), }); export const __Field = new GraphQLObjectType({ @@ -359,7 +359,7 @@ export const __Field = new GraphQLObjectType({ type: GraphQLString, resolve: (field) => field.deprecationReason, }, - }: GraphQLFieldConfigMap, mixed>), + } as GraphQLFieldConfigMap, unknown>), }); export const __InputValue = new GraphQLObjectType({ @@ -398,7 +398,7 @@ export const __InputValue = new GraphQLObjectType({ type: GraphQLString, resolve: (obj) => obj.deprecationReason, }, - }: GraphQLFieldConfigMap), + } as GraphQLFieldConfigMap), }); export const __EnumValue = new GraphQLObjectType({ @@ -423,7 +423,7 @@ export const __EnumValue = new GraphQLObjectType({ type: GraphQLString, resolve: (enumValue) => enumValue.deprecationReason, }, - }: GraphQLFieldConfigMap), + } as GraphQLFieldConfigMap), }); export const TypeKind = Object.freeze({ @@ -486,8 +486,7 @@ export const __TypeKind = new GraphQLEnumType({ * Note that these are GraphQLField and not GraphQLFieldConfig, * so the format for args is different. */ - -export const SchemaMetaFieldDef: GraphQLField = { +export const SchemaMetaFieldDef: GraphQLField = { name: '__schema', type: new GraphQLNonNull(__Schema), description: 'Access the current type schema of this server.', @@ -498,7 +497,7 @@ export const SchemaMetaFieldDef: GraphQLField = { astNode: undefined, }; -export const TypeMetaFieldDef: GraphQLField = { +export const TypeMetaFieldDef: GraphQLField = { name: '__type', type: __Type, description: 'Request the type information of a single type.', @@ -519,7 +518,7 @@ export const TypeMetaFieldDef: GraphQLField = { astNode: undefined, }; -export const TypeNameMetaFieldDef: GraphQLField = { +export const TypeNameMetaFieldDef: GraphQLField = { name: '__typename', type: new GraphQLNonNull(GraphQLString), description: 'The name of the current Object type at runtime.', @@ -541,6 +540,6 @@ export const introspectionTypes = Object.freeze([ __TypeKind, ]); -export function isIntrospectionType(type: GraphQLNamedType): boolean %checks { +export function isIntrospectionType(type: GraphQLNamedType): boolean { return introspectionTypes.some(({ name }) => type.name === name); } diff --git a/src/type/scalars.js b/src/type/scalars.ts similarity index 92% rename from src/type/scalars.js rename to src/type/scalars.ts index e02d2e5c6c1..5cb2fbac312 100644 --- a/src/type/scalars.js +++ b/src/type/scalars.ts @@ -6,7 +6,7 @@ import { print } from '../language/printer'; import { GraphQLError } from '../error/GraphQLError'; -import type { GraphQLNamedType } from './definition'; +import { GraphQLNamedType } from './definition'; import { GraphQLScalarType } from './definition'; // As per the GraphQL Spec, Integers are only treated as valid when a valid @@ -17,7 +17,7 @@ import { GraphQLScalarType } from './definition'; const MAX_INT = 2147483647; const MIN_INT = -2147483648; -function serializeInt(outputValue: mixed): number { +function serializeInt(outputValue: unknown): number { const coercedValue = serializeObject(outputValue); if (typeof coercedValue === 'boolean') { @@ -43,7 +43,7 @@ function serializeInt(outputValue: mixed): number { return num; } -function coerceInt(inputValue: mixed): number { +function coerceInt(inputValue: unknown): number { if (typeof inputValue !== 'number' || !Number.isInteger(inputValue)) { throw new GraphQLError( `Int cannot represent non-integer value: ${inspect(inputValue)}`, @@ -81,7 +81,7 @@ export const GraphQLInt = new GraphQLScalarType({ }, }); -function serializeFloat(outputValue: mixed): number { +function serializeFloat(outputValue: unknown): number { const coercedValue = serializeObject(outputValue); if (typeof coercedValue === 'boolean') { @@ -101,7 +101,7 @@ function serializeFloat(outputValue: mixed): number { return num; } -function coerceFloat(inputValue: mixed): number { +function coerceFloat(inputValue: unknown): number { if (typeof inputValue !== 'number' || !Number.isFinite(inputValue)) { throw new GraphQLError( `Float cannot represent non numeric value: ${inspect(inputValue)}`, @@ -130,7 +130,7 @@ export const GraphQLFloat = new GraphQLScalarType({ // Support serializing objects with custom valueOf() or toJSON() functions - // a common way to represent a complex value which can be represented as // a string (ex: MongoDB id objects). -function serializeObject(outputValue: mixed): mixed { +function serializeObject(outputValue: unknown): unknown { if (isObjectLike(outputValue)) { if (typeof outputValue.valueOf === 'function') { const valueOfResult = outputValue.valueOf(); @@ -146,7 +146,7 @@ function serializeObject(outputValue: mixed): mixed { return outputValue; } -function serializeString(outputValue: mixed): string { +function serializeString(outputValue: unknown): string { const coercedValue = serializeObject(outputValue); // Serialize string, boolean and number values to a string, but do not @@ -165,7 +165,7 @@ function serializeString(outputValue: mixed): string { ); } -function coerceString(inputValue: mixed): string { +function coerceString(inputValue: unknown): string { if (typeof inputValue !== 'string') { throw new GraphQLError( `String cannot represent a non string value: ${inspect(inputValue)}`, @@ -191,7 +191,7 @@ export const GraphQLString = new GraphQLScalarType({ }, }); -function serializeBoolean(outputValue: mixed): boolean { +function serializeBoolean(outputValue: unknown): boolean { const coercedValue = serializeObject(outputValue); if (typeof coercedValue === 'boolean') { @@ -205,7 +205,7 @@ function serializeBoolean(outputValue: mixed): boolean { ); } -function coerceBoolean(inputValue: mixed): boolean { +function coerceBoolean(inputValue: unknown): boolean { if (typeof inputValue !== 'boolean') { throw new GraphQLError( `Boolean cannot represent a non boolean value: ${inspect(inputValue)}`, @@ -230,7 +230,7 @@ export const GraphQLBoolean = new GraphQLScalarType({ }, }); -function serializeID(outputValue: mixed): string { +function serializeID(outputValue: unknown): string { const coercedValue = serializeObject(outputValue); if (typeof coercedValue === 'string') { @@ -242,7 +242,7 @@ function serializeID(outputValue: mixed): string { throw new GraphQLError(`ID cannot represent value: ${inspect(outputValue)}`); } -function coerceID(inputValue: mixed): string { +function coerceID(inputValue: unknown): string { if (typeof inputValue === 'string') { return inputValue; } @@ -278,6 +278,6 @@ export const specifiedScalarTypes = Object.freeze([ GraphQLID, ]); -export function isSpecifiedScalarType(type: GraphQLNamedType): boolean %checks { +export function isSpecifiedScalarType(type: GraphQLNamedType): boolean { return specifiedScalarTypes.some(({ name }) => type.name === name); } diff --git a/src/type/schema.js b/src/type/schema.ts similarity index 81% rename from src/type/schema.js rename to src/type/schema.ts index 521540c1853..d7a46392d04 100644 --- a/src/type/schema.js +++ b/src/type/schema.ts @@ -1,24 +1,18 @@ +import { $ReadOnly } from 'utility-types'; import objectValues from '../polyfills/objectValues'; -import type { - ObjMap, - ReadOnlyObjMap, - ReadOnlyObjMapLike, -} from '../jsutils/ObjMap'; +import { ObjMap, ReadOnlyObjMap, ReadOnlyObjMapLike } from '../jsutils/ObjMap'; import inspect from '../jsutils/inspect'; import toObjMap from '../jsutils/toObjMap'; import devAssert from '../jsutils/devAssert'; import instanceOf from '../jsutils/instanceOf'; import isObjectLike from '../jsutils/isObjectLike'; -import type { GraphQLError } from '../error/GraphQLError'; +import { GraphQLError } from '../error/GraphQLError'; -import type { - SchemaDefinitionNode, - SchemaExtensionNode, -} from '../language/ast'; +import { SchemaDefinitionNode, SchemaExtensionNode } from '../language/ast'; -import type { +import { GraphQLType, GraphQLNamedType, GraphQLAbstractType, @@ -42,14 +36,13 @@ import { /** * Test if the given value is a GraphQL schema. */ -declare function isSchema(schema: mixed): boolean %checks(schema instanceof - GraphQLSchema); +declare function isSchema(schema: unknown): boolean; // eslint-disable-next-line no-redeclare export function isSchema(schema) { return instanceOf(schema, GraphQLSchema); } -export function assertSchema(schema: mixed): GraphQLSchema { +export function assertSchema(schema: unknown): GraphQLSchema { if (!isSchema(schema)) { throw new Error(`Expected ${inspect(schema)} to be a GraphQL schema.`); } @@ -120,24 +113,24 @@ export function assertSchema(schema: mixed): GraphQLSchema { * */ export class GraphQLSchema { - description: ?string; - extensions: ?ReadOnlyObjMap; - astNode: ?SchemaDefinitionNode; - extensionASTNodes: ?$ReadOnlyArray; - - _queryType: ?GraphQLObjectType; - _mutationType: ?GraphQLObjectType; - _subscriptionType: ?GraphQLObjectType; - _directives: $ReadOnlyArray; + description: string | null | undefined; + extensions: ReadOnlyObjMap | null | undefined; + astNode: SchemaDefinitionNode | null | undefined; + extensionASTNodes: ReadonlyArray | null | undefined; + + _queryType: GraphQLObjectType | null | undefined; + _mutationType: GraphQLObjectType | null | undefined; + _subscriptionType: GraphQLObjectType | null | undefined; + _directives: ReadonlyArray; _typeMap: TypeMap; _subTypeMap: ObjMap>; - _implementationsMap: ObjMap<{| - objects: Array, - interfaces: Array, - |}>; + _implementationsMap: ObjMap<{ + objects: Array; + interfaces: Array; + }>; // Used as a cache for validateSchema(). - __validationErrors: ?$ReadOnlyArray; + __validationErrors: ReadonlyArray | null | undefined; constructor(config: $ReadOnly): void { // If this schema was built from a source known to be valid, then it may be @@ -256,15 +249,15 @@ export class GraphQLSchema { } } - getQueryType(): ?GraphQLObjectType { + getQueryType(): GraphQLObjectType | null | undefined { return this._queryType; } - getMutationType(): ?GraphQLObjectType { + getMutationType(): GraphQLObjectType | null | undefined { return this._mutationType; } - getSubscriptionType(): ?GraphQLObjectType { + getSubscriptionType(): GraphQLObjectType | null | undefined { return this._subscriptionType; } @@ -272,13 +265,13 @@ export class GraphQLSchema { return this._typeMap; } - getType(name: string): ?GraphQLNamedType { + getType(name: string): GraphQLNamedType | null | undefined { return this.getTypeMap()[name]; } getPossibleTypes( abstractType: GraphQLAbstractType, - ): $ReadOnlyArray { + ): ReadonlyArray { return isUnionType(abstractType) ? abstractType.getTypes() : this.getImplementations(abstractType).objects; @@ -286,10 +279,12 @@ export class GraphQLSchema { getImplementations( interfaceType: GraphQLInterfaceType, - ): {| - objects: /* $ReadOnly */ Array, - interfaces: /* $ReadOnly */ Array, - |} { + ): { + objects: /* $ReadOnly */ + Array; + interfaces: /* $ReadOnly */ + Array; + } { const implementations = this._implementationsMap[interfaceType.name]; return implementations ?? { objects: [], interfaces: [] }; } @@ -321,11 +316,11 @@ export class GraphQLSchema { return map[maybeSubType.name] !== undefined; } - getDirectives(): $ReadOnlyArray { + getDirectives(): ReadonlyArray { return this._directives; } - getDirective(name: string): ?GraphQLDirective { + getDirective(name: string): GraphQLDirective | null | undefined { return this.getDirectives().find((directive) => directive.name === name); } @@ -352,7 +347,7 @@ export class GraphQLSchema { type TypeMap = ObjMap; -export type GraphQLSchemaValidationOptions = {| +export type GraphQLSchemaValidationOptions = { /** * When building a schema from a GraphQL service's introspection result, it * might be safe to assume the schema is valid. Set to true to assume the @@ -360,34 +355,32 @@ export type GraphQLSchemaValidationOptions = {| * * Default: false */ - assumeValid?: boolean, -|}; - -export type GraphQLSchemaConfig = {| - description?: ?string, - query?: ?GraphQLObjectType, - mutation?: ?GraphQLObjectType, - subscription?: ?GraphQLObjectType, - types?: ?Array, - directives?: ?Array, - extensions?: ?ReadOnlyObjMapLike, - astNode?: ?SchemaDefinitionNode, - extensionASTNodes?: ?$ReadOnlyArray, - ...GraphQLSchemaValidationOptions, -|}; + assumeValid?: boolean; +}; + +export type GraphQLSchemaConfig = GraphQLSchemaValidationOptions & { + description?: string | null | undefined; + query?: GraphQLObjectType | null | undefined; + mutation?: GraphQLObjectType | null | undefined; + subscription?: GraphQLObjectType | null | undefined; + types?: Array | null | undefined; + directives?: Array | null | undefined; + extensions?: ReadOnlyObjMapLike | null | undefined; + astNode?: SchemaDefinitionNode | null | undefined; + extensionASTNodes?: ReadonlyArray | null | undefined; +}; /** * @internal */ -export type GraphQLSchemaNormalizedConfig = {| - ...GraphQLSchemaConfig, - description: ?string, - types: Array, - directives: Array, - extensions: ?ReadOnlyObjMap, - extensionASTNodes: $ReadOnlyArray, - assumeValid: boolean, -|}; +export type GraphQLSchemaNormalizedConfig = GraphQLSchemaConfig & { + description: string | null | undefined; + types: Array; + directives: Array; + extensions: ReadOnlyObjMap | null | undefined; + extensionASTNodes: ReadonlyArray; + assumeValid: boolean; +}; function collectReferencedTypes( type: GraphQLType, diff --git a/src/type/validate.js b/src/type/validate.js deleted file mode 100644 index f0075e2b9e7..00000000000 --- a/src/type/validate.js +++ /dev/null @@ -1,668 +0,0 @@ -import objectValues from '../polyfills/objectValues'; - -import inspect from '../jsutils/inspect'; - -import { GraphQLError } from '../error/GraphQLError'; -import { locatedError } from '../error/locatedError'; - -import type { - ASTNode, - NamedTypeNode, - DirectiveNode, - OperationTypeNode, -} from '../language/ast'; - -import { isValidNameError } from '../utilities/assertValidName'; -import { isEqualType, isTypeSubTypeOf } from '../utilities/typeComparators'; - -import type { GraphQLSchema } from './schema'; -import type { - GraphQLObjectType, - GraphQLInterfaceType, - GraphQLUnionType, - GraphQLEnumType, - GraphQLInputObjectType, -} from './definition'; -import { assertSchema } from './schema'; -import { isIntrospectionType } from './introspection'; -import { isDirective, GraphQLDeprecatedDirective } from './directives'; -import { - isObjectType, - isInterfaceType, - isUnionType, - isEnumType, - isInputObjectType, - isNamedType, - isNonNullType, - isInputType, - isOutputType, - isRequiredArgument, - isRequiredInputField, -} from './definition'; - -/** - * Implements the "Type Validation" sub-sections of the specification's - * "Type System" section. - * - * Validation runs synchronously, returning an array of encountered errors, or - * an empty array if no errors were encountered and the Schema is valid. - */ -export function validateSchema( - schema: GraphQLSchema, -): $ReadOnlyArray { - // First check to ensure the provided value is in fact a GraphQLSchema. - assertSchema(schema); - - // If this Schema has already been validated, return the previous results. - if (schema.__validationErrors) { - return schema.__validationErrors; - } - - // Validate the schema, producing a list of errors. - const context = new SchemaValidationContext(schema); - validateRootTypes(context); - validateDirectives(context); - validateTypes(context); - - // Persist the results of validation before returning to ensure validation - // does not run multiple times for this schema. - const errors = context.getErrors(); - schema.__validationErrors = errors; - return errors; -} - -/** - * Utility function which asserts a schema is valid by throwing an error if - * it is invalid. - */ -export function assertValidSchema(schema: GraphQLSchema): void { - const errors = validateSchema(schema); - if (errors.length !== 0) { - throw new Error(errors.map((error) => error.message).join('\n\n')); - } -} - -class SchemaValidationContext { - +_errors: Array; - +schema: GraphQLSchema; - - constructor(schema) { - this._errors = []; - this.schema = schema; - } - - reportError( - message: string, - nodes?: $ReadOnlyArray | ?ASTNode, - ): void { - const _nodes = Array.isArray(nodes) ? nodes.filter(Boolean) : nodes; - this.addError(new GraphQLError(message, _nodes)); - } - - addError(error: GraphQLError): void { - this._errors.push(error); - } - - getErrors(): $ReadOnlyArray { - return this._errors; - } -} - -function validateRootTypes(context: SchemaValidationContext): void { - const schema = context.schema; - const queryType = schema.getQueryType(); - if (!queryType) { - context.reportError('Query root type must be provided.', schema.astNode); - } else if (!isObjectType(queryType)) { - context.reportError( - `Query root type must be Object type, it cannot be ${inspect( - queryType, - )}.`, - getOperationTypeNode(schema, 'query') ?? queryType.astNode, - ); - } - - const mutationType = schema.getMutationType(); - if (mutationType && !isObjectType(mutationType)) { - context.reportError( - 'Mutation root type must be Object type if provided, it cannot be ' + - `${inspect(mutationType)}.`, - getOperationTypeNode(schema, 'mutation') ?? mutationType.astNode, - ); - } - - const subscriptionType = schema.getSubscriptionType(); - if (subscriptionType && !isObjectType(subscriptionType)) { - context.reportError( - 'Subscription root type must be Object type if provided, it cannot be ' + - `${inspect(subscriptionType)}.`, - getOperationTypeNode(schema, 'subscription') ?? subscriptionType.astNode, - ); - } -} - -function getOperationTypeNode( - schema: GraphQLSchema, - operation: OperationTypeNode, -): ?ASTNode { - const operationNodes = getAllSubNodes(schema, (node) => node.operationTypes); - for (const node of operationNodes) { - if (node.operation === operation) { - return node.type; - } - } - return undefined; -} - -function validateDirectives(context: SchemaValidationContext): void { - for (const directive of context.schema.getDirectives()) { - // Ensure all directives are in fact GraphQL directives. - if (!isDirective(directive)) { - context.reportError( - `Expected directive but got: ${inspect(directive)}.`, - directive?.astNode, - ); - continue; - } - - // Ensure they are named correctly. - validateName(context, directive); - - // TODO: Ensure proper locations. - - // Ensure the arguments are valid. - for (const arg of directive.args) { - // Ensure they are named correctly. - validateName(context, arg); - - // Ensure the type is an input type. - if (!isInputType(arg.type)) { - context.reportError( - `The type of @${directive.name}(${arg.name}:) must be Input Type ` + - `but got: ${inspect(arg.type)}.`, - arg.astNode, - ); - } - - if (isRequiredArgument(arg) && arg.deprecationReason != null) { - context.reportError( - `Required argument @${directive.name}(${arg.name}:) cannot be deprecated.`, - [ - getDeprecatedDirectiveNode(arg.astNode), - // istanbul ignore next (TODO need to write coverage tests) - arg.astNode?.type, - ], - ); - } - } - } -} - -function validateName( - context: SchemaValidationContext, - node: { +name: string, +astNode: ?ASTNode, ... }, -): void { - // Ensure names are valid, however introspection types opt out. - const error = isValidNameError(node.name); - if (error) { - context.addError(locatedError(error, node.astNode)); - } -} - -function validateTypes(context: SchemaValidationContext): void { - const validateInputObjectCircularRefs = createInputObjectCircularRefsValidator( - context, - ); - const typeMap = context.schema.getTypeMap(); - for (const type of objectValues(typeMap)) { - // Ensure all provided types are in fact GraphQL type. - if (!isNamedType(type)) { - context.reportError( - `Expected GraphQL named type but got: ${inspect(type)}.`, - type.astNode, - ); - continue; - } - - // Ensure it is named correctly (excluding introspection types). - if (!isIntrospectionType(type)) { - validateName(context, type); - } - - if (isObjectType(type)) { - // Ensure fields are valid - validateFields(context, type); - - // Ensure objects implement the interfaces they claim to. - validateInterfaces(context, type); - } else if (isInterfaceType(type)) { - // Ensure fields are valid. - validateFields(context, type); - - // Ensure interfaces implement the interfaces they claim to. - validateInterfaces(context, type); - } else if (isUnionType(type)) { - // Ensure Unions include valid member types. - validateUnionMembers(context, type); - } else if (isEnumType(type)) { - // Ensure Enums have valid values. - validateEnumValues(context, type); - } else if (isInputObjectType(type)) { - // Ensure Input Object fields are valid. - validateInputFields(context, type); - - // Ensure Input Objects do not contain non-nullable circular references - validateInputObjectCircularRefs(type); - } - } -} - -function validateFields( - context: SchemaValidationContext, - type: GraphQLObjectType | GraphQLInterfaceType, -): void { - const fields = objectValues(type.getFields()); - - // Objects and Interfaces both must define one or more fields. - if (fields.length === 0) { - context.reportError( - `Type ${type.name} must define one or more fields.`, - getAllNodes(type), - ); - } - - for (const field of fields) { - // Ensure they are named correctly. - validateName(context, field); - - // Ensure the type is an output type - if (!isOutputType(field.type)) { - context.reportError( - `The type of ${type.name}.${field.name} must be Output Type ` + - `but got: ${inspect(field.type)}.`, - field.astNode?.type, - ); - } - - // Ensure the arguments are valid - for (const arg of field.args) { - const argName = arg.name; - - // Ensure they are named correctly. - validateName(context, arg); - - // Ensure the type is an input type - if (!isInputType(arg.type)) { - context.reportError( - `The type of ${type.name}.${field.name}(${argName}:) must be Input ` + - `Type but got: ${inspect(arg.type)}.`, - arg.astNode?.type, - ); - } - - if (isRequiredArgument(arg) && arg.deprecationReason != null) { - context.reportError( - `Required argument ${type.name}.${field.name}(${argName}:) cannot be deprecated.`, - [ - getDeprecatedDirectiveNode(arg.astNode), - // istanbul ignore next (TODO need to write coverage tests) - arg.astNode?.type, - ], - ); - } - } - } -} - -function validateInterfaces( - context: SchemaValidationContext, - type: GraphQLObjectType | GraphQLInterfaceType, -): void { - const ifaceTypeNames = Object.create(null); - for (const iface of type.getInterfaces()) { - if (!isInterfaceType(iface)) { - context.reportError( - `Type ${inspect(type)} must only implement Interface types, ` + - `it cannot implement ${inspect(iface)}.`, - getAllImplementsInterfaceNodes(type, iface), - ); - continue; - } - - if (type === iface) { - context.reportError( - `Type ${type.name} cannot implement itself because it would create a circular reference.`, - getAllImplementsInterfaceNodes(type, iface), - ); - continue; - } - - if (ifaceTypeNames[iface.name]) { - context.reportError( - `Type ${type.name} can only implement ${iface.name} once.`, - getAllImplementsInterfaceNodes(type, iface), - ); - continue; - } - - ifaceTypeNames[iface.name] = true; - - validateTypeImplementsAncestors(context, type, iface); - validateTypeImplementsInterface(context, type, iface); - } -} - -function validateTypeImplementsInterface( - context: SchemaValidationContext, - type: GraphQLObjectType | GraphQLInterfaceType, - iface: GraphQLInterfaceType, -): void { - const typeFieldMap = type.getFields(); - - // Assert each interface field is implemented. - for (const ifaceField of objectValues(iface.getFields())) { - const fieldName = ifaceField.name; - const typeField = typeFieldMap[fieldName]; - - // Assert interface field exists on type. - if (!typeField) { - context.reportError( - `Interface field ${iface.name}.${fieldName} expected but ${type.name} does not provide it.`, - [ifaceField.astNode, ...getAllNodes(type)], - ); - continue; - } - - // Assert interface field type is satisfied by type field type, by being - // a valid subtype. (covariant) - if (!isTypeSubTypeOf(context.schema, typeField.type, ifaceField.type)) { - context.reportError( - `Interface field ${iface.name}.${fieldName} expects type ` + - `${inspect(ifaceField.type)} but ${type.name}.${fieldName} ` + - `is type ${inspect(typeField.type)}.`, - [ - // istanbul ignore next (TODO need to write coverage tests) - ifaceField.astNode?.type, - // istanbul ignore next (TODO need to write coverage tests) - typeField.astNode?.type, - ], - ); - } - - // Assert each interface field arg is implemented. - for (const ifaceArg of ifaceField.args) { - const argName = ifaceArg.name; - const typeArg = typeField.args.find((arg) => arg.name === argName); - - // Assert interface field arg exists on object field. - if (!typeArg) { - context.reportError( - `Interface field argument ${iface.name}.${fieldName}(${argName}:) expected but ${type.name}.${fieldName} does not provide it.`, - [ifaceArg.astNode, typeField.astNode], - ); - continue; - } - - // Assert interface field arg type matches object field arg type. - // (invariant) - // TODO: change to contravariant? - if (!isEqualType(ifaceArg.type, typeArg.type)) { - context.reportError( - `Interface field argument ${iface.name}.${fieldName}(${argName}:) ` + - `expects type ${inspect(ifaceArg.type)} but ` + - `${type.name}.${fieldName}(${argName}:) is type ` + - `${inspect(typeArg.type)}.`, - [ - // istanbul ignore next (TODO need to write coverage tests) - ifaceArg.astNode?.type, - // istanbul ignore next (TODO need to write coverage tests) - typeArg.astNode?.type, - ], - ); - } - - // TODO: validate default values? - } - - // Assert additional arguments must not be required. - for (const typeArg of typeField.args) { - const argName = typeArg.name; - const ifaceArg = ifaceField.args.find((arg) => arg.name === argName); - if (!ifaceArg && isRequiredArgument(typeArg)) { - context.reportError( - `Object field ${type.name}.${fieldName} includes required argument ${argName} that is missing from the Interface field ${iface.name}.${fieldName}.`, - [typeArg.astNode, ifaceField.astNode], - ); - } - } - } -} - -function validateTypeImplementsAncestors( - context: SchemaValidationContext, - type: GraphQLObjectType | GraphQLInterfaceType, - iface: GraphQLInterfaceType, -): void { - const ifaceInterfaces = type.getInterfaces(); - for (const transitive of iface.getInterfaces()) { - if (ifaceInterfaces.indexOf(transitive) === -1) { - context.reportError( - transitive === type - ? `Type ${type.name} cannot implement ${iface.name} because it would create a circular reference.` - : `Type ${type.name} must implement ${transitive.name} because it is implemented by ${iface.name}.`, - [ - ...getAllImplementsInterfaceNodes(iface, transitive), - ...getAllImplementsInterfaceNodes(type, iface), - ], - ); - } - } -} - -function validateUnionMembers( - context: SchemaValidationContext, - union: GraphQLUnionType, -): void { - const memberTypes = union.getTypes(); - - if (memberTypes.length === 0) { - context.reportError( - `Union type ${union.name} must define one or more member types.`, - getAllNodes(union), - ); - } - - const includedTypeNames = Object.create(null); - for (const memberType of memberTypes) { - if (includedTypeNames[memberType.name]) { - context.reportError( - `Union type ${union.name} can only include type ${memberType.name} once.`, - getUnionMemberTypeNodes(union, memberType.name), - ); - continue; - } - includedTypeNames[memberType.name] = true; - if (!isObjectType(memberType)) { - context.reportError( - `Union type ${union.name} can only include Object types, ` + - `it cannot include ${inspect(memberType)}.`, - getUnionMemberTypeNodes(union, String(memberType)), - ); - } - } -} - -function validateEnumValues( - context: SchemaValidationContext, - enumType: GraphQLEnumType, -): void { - const enumValues = enumType.getValues(); - - if (enumValues.length === 0) { - context.reportError( - `Enum type ${enumType.name} must define one or more values.`, - getAllNodes(enumType), - ); - } - - for (const enumValue of enumValues) { - const valueName = enumValue.name; - - // Ensure valid name. - validateName(context, enumValue); - if (valueName === 'true' || valueName === 'false' || valueName === 'null') { - context.reportError( - `Enum type ${enumType.name} cannot include value: ${valueName}.`, - enumValue.astNode, - ); - } - } -} - -function validateInputFields( - context: SchemaValidationContext, - inputObj: GraphQLInputObjectType, -): void { - const fields = objectValues(inputObj.getFields()); - - if (fields.length === 0) { - context.reportError( - `Input Object type ${inputObj.name} must define one or more fields.`, - getAllNodes(inputObj), - ); - } - - // Ensure the arguments are valid - for (const field of fields) { - // Ensure they are named correctly. - validateName(context, field); - - // Ensure the type is an input type - if (!isInputType(field.type)) { - context.reportError( - `The type of ${inputObj.name}.${field.name} must be Input Type ` + - `but got: ${inspect(field.type)}.`, - field.astNode?.type, - ); - } - - if (isRequiredInputField(field) && field.deprecationReason != null) { - context.reportError( - `Required input field ${inputObj.name}.${field.name} cannot be deprecated.`, - [ - getDeprecatedDirectiveNode(field.astNode), - // istanbul ignore next (TODO need to write coverage tests) - field.astNode?.type, - ], - ); - } - } -} - -function createInputObjectCircularRefsValidator( - context: SchemaValidationContext, -): (GraphQLInputObjectType) => void { - // Modified copy of algorithm from 'src/validation/rules/NoFragmentCycles.js'. - // Tracks already visited types to maintain O(N) and to ensure that cycles - // are not redundantly reported. - const visitedTypes = Object.create(null); - - // Array of types nodes used to produce meaningful errors - const fieldPath = []; - - // Position in the type path - const fieldPathIndexByTypeName = Object.create(null); - - return detectCycleRecursive; - - // This does a straight-forward DFS to find cycles. - // It does not terminate when a cycle was found but continues to explore - // the graph to find all possible cycles. - function detectCycleRecursive(inputObj: GraphQLInputObjectType): void { - if (visitedTypes[inputObj.name]) { - return; - } - - visitedTypes[inputObj.name] = true; - fieldPathIndexByTypeName[inputObj.name] = fieldPath.length; - - const fields = objectValues(inputObj.getFields()); - for (const field of fields) { - if (isNonNullType(field.type) && isInputObjectType(field.type.ofType)) { - const fieldType = field.type.ofType; - const cycleIndex = fieldPathIndexByTypeName[fieldType.name]; - - fieldPath.push(field); - if (cycleIndex === undefined) { - detectCycleRecursive(fieldType); - } else { - const cyclePath = fieldPath.slice(cycleIndex); - const pathStr = cyclePath.map((fieldObj) => fieldObj.name).join('.'); - context.reportError( - `Cannot reference Input Object "${fieldType.name}" within itself through a series of non-null fields: "${pathStr}".`, - cyclePath.map((fieldObj) => fieldObj.astNode), - ); - } - fieldPath.pop(); - } - } - - fieldPathIndexByTypeName[inputObj.name] = undefined; - } -} - -type SDLDefinedObject = { - +astNode: ?T, - +extensionASTNodes?: ?$ReadOnlyArray, - ... -}; - -function getAllNodes( - object: SDLDefinedObject, -): $ReadOnlyArray { - const { astNode, extensionASTNodes } = object; - return astNode - ? extensionASTNodes - ? [astNode].concat(extensionASTNodes) - : [astNode] - : extensionASTNodes ?? []; -} - -function getAllSubNodes( - object: SDLDefinedObject, - getter: (T | K) => ?(L | $ReadOnlyArray), -): $ReadOnlyArray { - let subNodes = []; - for (const node of getAllNodes(object)) { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - subNodes = subNodes.concat(getter(node) ?? []); - } - return subNodes; -} - -function getAllImplementsInterfaceNodes( - type: GraphQLObjectType | GraphQLInterfaceType, - iface: GraphQLInterfaceType, -): $ReadOnlyArray { - return getAllSubNodes(type, (typeNode) => typeNode.interfaces).filter( - (ifaceNode) => ifaceNode.name.value === iface.name, - ); -} - -function getUnionMemberTypeNodes( - union: GraphQLUnionType, - typeName: string, -): ?$ReadOnlyArray { - return getAllSubNodes(union, (unionNode) => unionNode.types).filter( - (typeNode) => typeNode.name.value === typeName, - ); -} - -function getDeprecatedDirectiveNode( - definitionNode: ?{ +directives?: $ReadOnlyArray, ... }, -): ?DirectiveNode { - // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - return definitionNode?.directives?.find( - (node) => node.name.value === GraphQLDeprecatedDirective.name, - ); -} diff --git a/src/type/validate.ts b/src/type/validate.ts new file mode 100644 index 00000000000..604862c121f --- /dev/null +++ b/src/type/validate.ts @@ -0,0 +1,466 @@ +import objectValues from "../polyfills/objectValues"; + +import inspect from "../jsutils/inspect"; + +import { GraphQLError } from "../error/GraphQLError"; +import { locatedError } from "../error/locatedError"; + +import { ASTNode, NamedTypeNode, DirectiveNode, OperationTypeNode } from "../language/ast"; + +import { isValidNameError } from "../utilities/assertValidName"; +import { isEqualType, isTypeSubTypeOf } from "../utilities/typeComparators"; + +import { GraphQLSchema } from "./schema"; +import { GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType } from "./definition"; +import { assertSchema } from "./schema"; +import { isIntrospectionType } from "./introspection"; +import { isDirective, GraphQLDeprecatedDirective } from "./directives"; +import { isObjectType, isInterfaceType, isUnionType, isEnumType, isInputObjectType, isNamedType, isNonNullType, isInputType, isOutputType, isRequiredArgument, isRequiredInputField } from "./definition"; + +/** + * Implements the "Type Validation" sub-sections of the specification's + * "Type System" section. + * + * Validation runs synchronously, returning an array of encountered errors, or + * an empty array if no errors were encountered and the Schema is valid. + */ +export function validateSchema(schema: GraphQLSchema): ReadonlyArray { + // First check to ensure the provided value is in fact a GraphQLSchema. + assertSchema(schema); + + // If this Schema has already been validated, return the previous results. + if (schema.__validationErrors) { + return schema.__validationErrors; + } + + // Validate the schema, producing a list of errors. + const context = new SchemaValidationContext(schema); + validateRootTypes(context); + validateDirectives(context); + validateTypes(context); + + // Persist the results of validation before returning to ensure validation + // does not run multiple times for this schema. + const errors = context.getErrors(); + schema.__validationErrors = errors; + return errors; +} + +/** + * Utility function which asserts a schema is valid by throwing an error if + * it is invalid. + */ +export function assertValidSchema(schema: GraphQLSchema): void { + const errors = validateSchema(schema); + if (errors.length !== 0) { + throw new Error(errors.map(error => error.message).join('\n\n')); + } +} + +class SchemaValidationContext { + + +_errors: Array; + +schema: GraphQLSchema; + + constructor(schema) { + this._errors = []; + this.schema = schema; + } + + reportError(message: string, nodes?: ReadonlyArray | (ASTNode | null | undefined)): void { + const _nodes = Array.isArray(nodes) ? nodes.filter(Boolean) : nodes; + this.addError(new GraphQLError(message, _nodes)); + } + + addError(error: GraphQLError): void { + this._errors.push(error); + } + + getErrors(): ReadonlyArray { + return this._errors; + } +} + +function validateRootTypes(context: SchemaValidationContext): void { + const schema = context.schema; + const queryType = schema.getQueryType(); + if (!queryType) { + context.reportError('Query root type must be provided.', schema.astNode); + } else if (!isObjectType(queryType)) { + context.reportError(`Query root type must be Object type, it cannot be ${inspect(queryType)}.`, getOperationTypeNode(schema, 'query') ?? queryType.astNode); + } + + const mutationType = schema.getMutationType(); + if (mutationType && !isObjectType(mutationType)) { + context.reportError('Mutation root type must be Object type if provided, it cannot be ' + `${inspect(mutationType)}.`, getOperationTypeNode(schema, 'mutation') ?? mutationType.astNode); + } + + const subscriptionType = schema.getSubscriptionType(); + if (subscriptionType && !isObjectType(subscriptionType)) { + context.reportError('Subscription root type must be Object type if provided, it cannot be ' + `${inspect(subscriptionType)}.`, getOperationTypeNode(schema, 'subscription') ?? subscriptionType.astNode); + } +} + +function getOperationTypeNode(schema: GraphQLSchema, operation: OperationTypeNode): ASTNode | null | undefined { + const operationNodes = getAllSubNodes(schema, node => node.operationTypes); + for (const node of operationNodes) { + if (node.operation === operation) { + return node.type; + } + } + return undefined; +} + +function validateDirectives(context: SchemaValidationContext): void { + for (const directive of context.schema.getDirectives()) { + // Ensure all directives are in fact GraphQL directives. + if (!isDirective(directive)) { + context.reportError(`Expected directive but got: ${inspect(directive)}.`, (directive?.astNode)); + continue; + } + + // Ensure they are named correctly. + validateName(context, directive); + + // TODO: Ensure proper locations. + + // Ensure the arguments are valid. + for (const arg of directive.args) { + // Ensure they are named correctly. + validateName(context, arg); + + // Ensure the type is an input type. + if (!isInputType(arg.type)) { + context.reportError(`The type of @${directive.name}(${arg.name}:) must be Input Type ` + `but got: ${inspect(arg.type)}.`, arg.astNode); + } + + if (isRequiredArgument(arg) && arg.deprecationReason != null) { + context.reportError(`Required argument @${directive.name}(${arg.name}:) cannot be deprecated.`, [getDeprecatedDirectiveNode(arg.astNode), // istanbul ignore next (TODO need to write coverage tests) + arg.astNode?.type]); + } + } + } +} + +function validateName(context: SchemaValidationContext, node: {readonly name: string;readonly astNode: ASTNode | null | undefined;}): void { + // Ensure names are valid, however introspection types opt out. + const error = isValidNameError(node.name); + if (error) { + context.addError(locatedError(error, node.astNode)); + } +} + +function validateTypes(context: SchemaValidationContext): void { + const validateInputObjectCircularRefs = createInputObjectCircularRefsValidator(context); + const typeMap = context.schema.getTypeMap(); + for (const type of objectValues(typeMap)) { + // Ensure all provided types are in fact GraphQL type. + if (!isNamedType(type)) { + context.reportError(`Expected GraphQL named type but got: ${inspect(type)}.`, type.astNode); + continue; + } + + // Ensure it is named correctly (excluding introspection types). + if (!isIntrospectionType(type)) { + validateName(context, type); + } + + if (isObjectType(type)) { + // Ensure fields are valid + validateFields(context, type); + + // Ensure objects implement the interfaces they claim to. + validateInterfaces(context, type); + } else if (isInterfaceType(type)) { + // Ensure fields are valid. + validateFields(context, type); + + // Ensure interfaces implement the interfaces they claim to. + validateInterfaces(context, type); + } else if (isUnionType(type)) { + // Ensure Unions include valid member types. + validateUnionMembers(context, type); + } else if (isEnumType(type)) { + // Ensure Enums have valid values. + validateEnumValues(context, type); + } else if (isInputObjectType(type)) { + // Ensure Input Object fields are valid. + validateInputFields(context, type); + + // Ensure Input Objects do not contain non-nullable circular references + validateInputObjectCircularRefs(type); + } + } +} + +function validateFields(context: SchemaValidationContext, type: GraphQLObjectType | GraphQLInterfaceType): void { + const fields = objectValues(type.getFields()); + + // Objects and Interfaces both must define one or more fields. + if (fields.length === 0) { + context.reportError(`Type ${type.name} must define one or more fields.`, getAllNodes(type)); + } + + for (const field of fields) { + // Ensure they are named correctly. + validateName(context, field); + + // Ensure the type is an output type + if (!isOutputType(field.type)) { + context.reportError(`The type of ${type.name}.${field.name} must be Output Type ` + `but got: ${inspect(field.type)}.`, (field.astNode?.type)); + } + + // Ensure the arguments are valid + for (const arg of field.args) { + const argName = arg.name; + + // Ensure they are named correctly. + validateName(context, arg); + + // Ensure the type is an input type + if (!isInputType(arg.type)) { + context.reportError(`The type of ${type.name}.${field.name}(${argName}:) must be Input ` + `Type but got: ${inspect(arg.type)}.`, (arg.astNode?.type)); + } + + if (isRequiredArgument(arg) && arg.deprecationReason != null) { + context.reportError(`Required argument ${type.name}.${field.name}(${argName}:) cannot be deprecated.`, [getDeprecatedDirectiveNode(arg.astNode), // istanbul ignore next (TODO need to write coverage tests) + arg.astNode?.type]); + } + } + } +} + +function validateInterfaces(context: SchemaValidationContext, type: GraphQLObjectType | GraphQLInterfaceType): void { + const ifaceTypeNames = Object.create(null); + for (const iface of type.getInterfaces()) { + if (!isInterfaceType(iface)) { + context.reportError(`Type ${inspect(type)} must only implement Interface types, ` + `it cannot implement ${inspect(iface)}.`, getAllImplementsInterfaceNodes(type, iface)); + continue; + } + + if (type === iface) { + context.reportError(`Type ${type.name} cannot implement itself because it would create a circular reference.`, getAllImplementsInterfaceNodes(type, iface)); + continue; + } + + if (ifaceTypeNames[iface.name]) { + context.reportError(`Type ${type.name} can only implement ${iface.name} once.`, getAllImplementsInterfaceNodes(type, iface)); + continue; + } + + ifaceTypeNames[iface.name] = true; + + validateTypeImplementsAncestors(context, type, iface); + validateTypeImplementsInterface(context, type, iface); + } +} + +function validateTypeImplementsInterface(context: SchemaValidationContext, type: GraphQLObjectType | GraphQLInterfaceType, iface: GraphQLInterfaceType): void { + const typeFieldMap = type.getFields(); + + // Assert each interface field is implemented. + for (const ifaceField of objectValues(iface.getFields())) { + const fieldName = ifaceField.name; + const typeField = typeFieldMap[fieldName]; + + // Assert interface field exists on type. + if (!typeField) { + context.reportError(`Interface field ${iface.name}.${fieldName} expected but ${type.name} does not provide it.`, [ifaceField.astNode, ...getAllNodes(type)]); + continue; + } + + // Assert interface field type is satisfied by type field type, by being + // a valid subtype. (covariant) + if (!isTypeSubTypeOf(context.schema, typeField.type, ifaceField.type)) { + context.reportError(`Interface field ${iface.name}.${fieldName} expects type ` + `${inspect(ifaceField.type)} but ${type.name}.${fieldName} ` + `is type ${inspect(typeField.type)}.`, [// istanbul ignore next (TODO need to write coverage tests) + ifaceField.astNode?.type, // istanbul ignore next (TODO need to write coverage tests) + typeField.astNode?.type]); + } + + // Assert each interface field arg is implemented. + for (const ifaceArg of ifaceField.args) { + const argName = ifaceArg.name; + const typeArg = typeField.args.find(arg => arg.name === argName); + + // Assert interface field arg exists on object field. + if (!typeArg) { + context.reportError(`Interface field argument ${iface.name}.${fieldName}(${argName}:) expected but ${type.name}.${fieldName} does not provide it.`, [ifaceArg.astNode, typeField.astNode]); + continue; + } + + // Assert interface field arg type matches object field arg type. + // (invariant) + // TODO: change to contravariant? + if (!isEqualType(ifaceArg.type, typeArg.type)) { + context.reportError(`Interface field argument ${iface.name}.${fieldName}(${argName}:) ` + `expects type ${inspect(ifaceArg.type)} but ` + `${type.name}.${fieldName}(${argName}:) is type ` + `${inspect(typeArg.type)}.`, [// istanbul ignore next (TODO need to write coverage tests) + ifaceArg.astNode?.type, // istanbul ignore next (TODO need to write coverage tests) + typeArg.astNode?.type]); + } + + // TODO: validate default values? + } + + // Assert additional arguments must not be required. + for (const typeArg of typeField.args) { + const argName = typeArg.name; + const ifaceArg = ifaceField.args.find(arg => arg.name === argName); + if (!ifaceArg && isRequiredArgument(typeArg)) { + context.reportError(`Object field ${type.name}.${fieldName} includes required argument ${argName} that is missing from the Interface field ${iface.name}.${fieldName}.`, [typeArg.astNode, ifaceField.astNode]); + } + } + } +} + +function validateTypeImplementsAncestors(context: SchemaValidationContext, type: GraphQLObjectType | GraphQLInterfaceType, iface: GraphQLInterfaceType): void { + const ifaceInterfaces = type.getInterfaces(); + for (const transitive of iface.getInterfaces()) { + if (ifaceInterfaces.indexOf(transitive) === -1) { + context.reportError(transitive === type ? `Type ${type.name} cannot implement ${iface.name} because it would create a circular reference.` : `Type ${type.name} must implement ${transitive.name} because it is implemented by ${iface.name}.`, [...getAllImplementsInterfaceNodes(iface, transitive), ...getAllImplementsInterfaceNodes(type, iface)]); + } + } +} + +function validateUnionMembers(context: SchemaValidationContext, union: GraphQLUnionType): void { + const memberTypes = union.getTypes(); + + if (memberTypes.length === 0) { + context.reportError(`Union type ${union.name} must define one or more member types.`, getAllNodes(union)); + } + + const includedTypeNames = Object.create(null); + for (const memberType of memberTypes) { + if (includedTypeNames[memberType.name]) { + context.reportError(`Union type ${union.name} can only include type ${memberType.name} once.`, getUnionMemberTypeNodes(union, memberType.name)); + continue; + } + includedTypeNames[memberType.name] = true; + if (!isObjectType(memberType)) { + context.reportError(`Union type ${union.name} can only include Object types, ` + `it cannot include ${inspect(memberType)}.`, getUnionMemberTypeNodes(union, String(memberType))); + } + } +} + +function validateEnumValues(context: SchemaValidationContext, enumType: GraphQLEnumType): void { + const enumValues = enumType.getValues(); + + if (enumValues.length === 0) { + context.reportError(`Enum type ${enumType.name} must define one or more values.`, getAllNodes(enumType)); + } + + for (const enumValue of enumValues) { + const valueName = enumValue.name; + + // Ensure valid name. + validateName(context, enumValue); + if (valueName === 'true' || valueName === 'false' || valueName === 'null') { + context.reportError(`Enum type ${enumType.name} cannot include value: ${valueName}.`, enumValue.astNode); + } + } +} + +function validateInputFields(context: SchemaValidationContext, inputObj: GraphQLInputObjectType): void { + const fields = objectValues(inputObj.getFields()); + + if (fields.length === 0) { + context.reportError(`Input Object type ${inputObj.name} must define one or more fields.`, getAllNodes(inputObj)); + } + + // Ensure the arguments are valid + for (const field of fields) { + // Ensure they are named correctly. + validateName(context, field); + + // Ensure the type is an input type + if (!isInputType(field.type)) { + context.reportError(`The type of ${inputObj.name}.${field.name} must be Input Type ` + `but got: ${inspect(field.type)}.`, (field.astNode?.type)); + } + + if (isRequiredInputField(field) && field.deprecationReason != null) { + context.reportError(`Required input field ${inputObj.name}.${field.name} cannot be deprecated.`, [getDeprecatedDirectiveNode(field.astNode), // istanbul ignore next (TODO need to write coverage tests) + field.astNode?.type]); + } + } +} + +function createInputObjectCircularRefsValidator(context: SchemaValidationContext): (arg0: GraphQLInputObjectType) => void { + // Modified copy of algorithm from 'src/validation/rules/NoFragmentCycles.js'. + // Tracks already visited types to maintain O(N) and to ensure that cycles + // are not redundantly reported. + const visitedTypes = Object.create(null); + + // Array of types nodes used to produce meaningful errors + const fieldPath = []; + + // Position in the type path + const fieldPathIndexByTypeName = Object.create(null); + + return detectCycleRecursive; + + // This does a straight-forward DFS to find cycles. + // It does not terminate when a cycle was found but continues to explore + // the graph to find all possible cycles. + function detectCycleRecursive(inputObj: GraphQLInputObjectType): void { + if (visitedTypes[inputObj.name]) { + return; + } + + visitedTypes[inputObj.name] = true; + fieldPathIndexByTypeName[inputObj.name] = fieldPath.length; + + const fields = objectValues(inputObj.getFields()); + for (const field of fields) { + if (isNonNullType(field.type) && isInputObjectType(field.type.ofType)) { + const fieldType = field.type.ofType; + const cycleIndex = fieldPathIndexByTypeName[fieldType.name]; + + fieldPath.push(field); + if (cycleIndex === undefined) { + detectCycleRecursive(fieldType); + } else { + const cyclePath = fieldPath.slice(cycleIndex); + const pathStr = cyclePath.map(fieldObj => fieldObj.name).join('.'); + context.reportError(`Cannot reference Input Object "${fieldType.name}" within itself through a series of non-null fields: "${pathStr}".`, cyclePath.map(fieldObj => fieldObj.astNode)); + } + fieldPath.pop(); + } + } + + fieldPathIndexByTypeName[inputObj.name] = undefined; + } +} + +type SDLDefinedObject = { + readonly astNode: T | null | undefined; + readonly extensionASTNodes?: ReadonlyArray | null | undefined; + +}; + +function getAllNodes(object: SDLDefinedObject): ReadonlyArray { + const { + astNode, + extensionASTNodes + } = object; + return astNode ? extensionASTNodes ? [astNode].concat(extensionASTNodes) : [astNode] : extensionASTNodes ?? []; +} + +function getAllSubNodes(object: SDLDefinedObject, getter: (arg0: T | K) => (L | ReadonlyArray) | null | undefined): ReadonlyArray { + let subNodes = []; + for (const node of getAllNodes(object)) { + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') + subNodes = subNodes.concat(getter(node) ?? []); + } + return subNodes; +} + +function getAllImplementsInterfaceNodes(type: GraphQLObjectType | GraphQLInterfaceType, iface: GraphQLInterfaceType): ReadonlyArray { + return getAllSubNodes(type, typeNode => typeNode.interfaces).filter(ifaceNode => ifaceNode.name.value === iface.name); +} + +function getUnionMemberTypeNodes(union: GraphQLUnionType, typeName: string): ReadonlyArray | null | undefined { + return getAllSubNodes(union, unionNode => unionNode.types).filter(typeNode => typeNode.name.value === typeName); +} + +function getDeprecatedDirectiveNode(definitionNode: {readonly directives?: ReadonlyArray;} | null | undefined): DirectiveNode | null | undefined { + // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') + return definitionNode?.directives?.find(node => node.name.value === GraphQLDeprecatedDirective.name); +} \ No newline at end of file diff --git a/src/utilities/TypeInfo.js b/src/utilities/TypeInfo.ts similarity index 79% rename from src/utilities/TypeInfo.js rename to src/utilities/TypeInfo.ts index 4fdbef20152..136b15b3c3d 100644 --- a/src/utilities/TypeInfo.js +++ b/src/utilities/TypeInfo.ts @@ -1,12 +1,12 @@ -import type { Visitor } from '../language/visitor'; -import type { ASTNode, ASTKindToNode, FieldNode } from '../language/ast'; +import { Visitor } from '../language/visitor'; +import { ASTNode, ASTKindToNode, FieldNode } from '../language/ast'; import { Kind } from '../language/kinds'; import { isNode } from '../language/ast'; import { getVisitFn } from '../language/visitor'; -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLDirective } from '../type/directives'; -import type { +import { GraphQLSchema } from '../type/schema'; +import { GraphQLDirective } from '../type/directives'; +import { GraphQLType, GraphQLInputType, GraphQLOutputType, @@ -43,23 +43,21 @@ import { typeFromAST } from './typeFromAST'; */ export class TypeInfo { _schema: GraphQLSchema; - _typeStack: Array; - _parentTypeStack: Array; - _inputTypeStack: Array; - _fieldDefStack: Array>; - _defaultValueStack: Array; - _directive: ?GraphQLDirective; - _argument: ?GraphQLArgument; - _enumValue: ?GraphQLEnumValue; + _typeStack: Array; + _parentTypeStack: Array; + _inputTypeStack: Array; + _fieldDefStack: Array | null | undefined>; + _defaultValueStack: Array; + _directive: GraphQLDirective | null | undefined; + _argument: GraphQLArgument | null | undefined; + _enumValue: GraphQLEnumValue | null | undefined; _getFieldDef: typeof getFieldDef; constructor( - schema: GraphQLSchema, - // NOTE: this experimental optional second parameter is only needed in order + schema: GraphQLSchema, // NOTE: this experimental optional second parameter is only needed in order // to support non-spec-compliant code bases. You should never need to use it. // It may disappear in the future. - getFieldDefFn?: typeof getFieldDef, - // Initial type may be provided in rare cases to facilitate traversals + getFieldDefFn?: typeof getFieldDef, // Initial type may be provided in rare cases to facilitate traversals // beginning somewhere other than documents. initialType?: GraphQLType, ): void { @@ -86,51 +84,51 @@ export class TypeInfo { } } - getType(): ?GraphQLOutputType { + getType(): GraphQLOutputType | null | undefined { if (this._typeStack.length > 0) { return this._typeStack[this._typeStack.length - 1]; } } - getParentType(): ?GraphQLCompositeType { + getParentType(): GraphQLCompositeType | null | undefined { if (this._parentTypeStack.length > 0) { return this._parentTypeStack[this._parentTypeStack.length - 1]; } } - getInputType(): ?GraphQLInputType { + getInputType(): GraphQLInputType | null | undefined { if (this._inputTypeStack.length > 0) { return this._inputTypeStack[this._inputTypeStack.length - 1]; } } - getParentInputType(): ?GraphQLInputType { + getParentInputType(): GraphQLInputType | null | undefined { if (this._inputTypeStack.length > 1) { return this._inputTypeStack[this._inputTypeStack.length - 2]; } } - getFieldDef(): ?GraphQLField { + getFieldDef(): GraphQLField | null | undefined { if (this._fieldDefStack.length > 0) { return this._fieldDefStack[this._fieldDefStack.length - 1]; } } - getDefaultValue(): ?mixed { + getDefaultValue(): unknown | null | undefined { if (this._defaultValueStack.length > 0) { return this._defaultValueStack[this._defaultValueStack.length - 1]; } } - getDirective(): ?GraphQLDirective { + getDirective(): GraphQLDirective | null | undefined { return this._directive; } - getArgument(): ?GraphQLArgument { + getArgument(): GraphQLArgument | null | undefined { return this._argument; } - getEnumValue(): ?GraphQLEnumValue { + getEnumValue(): GraphQLEnumValue | null | undefined { return this._enumValue; } @@ -142,7 +140,7 @@ export class TypeInfo { // which occurs before guarantees of schema and document validity. switch (node.kind) { case Kind.SELECTION_SET: { - const namedType: mixed = getNamedType(this.getType()); + const namedType: unknown = getNamedType(this.getType()); this._parentTypeStack.push( isCompositeType(namedType) ? namedType : undefined, ); @@ -151,7 +149,7 @@ export class TypeInfo { case Kind.FIELD: { const parentType = this.getParentType(); let fieldDef; - let fieldType: mixed; + let fieldType: unknown; if (parentType) { fieldDef = this._getFieldDef(schema, parentType, node); if (fieldDef) { @@ -166,7 +164,7 @@ export class TypeInfo { this._directive = schema.getDirective(node.name.value); break; case Kind.OPERATION_DEFINITION: { - let type: mixed; + let type: unknown; switch (node.operation) { case 'query': type = schema.getQueryType(); @@ -184,14 +182,14 @@ export class TypeInfo { case Kind.INLINE_FRAGMENT: case Kind.FRAGMENT_DEFINITION: { const typeConditionAST = node.typeCondition; - const outputType: mixed = typeConditionAST + const outputType: unknown = typeConditionAST ? typeFromAST(schema, typeConditionAST) : getNamedType(this.getType()); this._typeStack.push(isOutputType(outputType) ? outputType : undefined); break; } case Kind.VARIABLE_DEFINITION: { - const inputType: mixed = typeFromAST(schema, node.type); + const inputType: unknown = typeFromAST(schema, node.type); this._inputTypeStack.push( isInputType(inputType) ? inputType : undefined, ); @@ -199,7 +197,7 @@ export class TypeInfo { } case Kind.ARGUMENT: { let argDef; - let argType: mixed; + let argType: unknown; const fieldOrDirective = this.getDirective() ?? this.getFieldDef(); if (fieldOrDirective) { argDef = fieldOrDirective.args.find( @@ -215,8 +213,8 @@ export class TypeInfo { break; } case Kind.LIST: { - const listType: mixed = getNullableType(this.getInputType()); - const itemType: mixed = isListType(listType) + const listType: unknown = getNullableType(this.getInputType()); + const itemType: unknown = isListType(listType) ? listType.ofType : listType; // List positions never have a default value. @@ -225,7 +223,7 @@ export class TypeInfo { break; } case Kind.OBJECT_FIELD: { - const objectType: mixed = getNamedType(this.getInputType()); + const objectType: unknown = getNamedType(this.getInputType()); let inputFieldType: GraphQLInputType | void; let inputField: GraphQLInputField | void; if (isInputObjectType(objectType)) { @@ -243,7 +241,7 @@ export class TypeInfo { break; } case Kind.ENUM: { - const enumType: mixed = getNamedType(this.getInputType()); + const enumType: unknown = getNamedType(this.getInputType()); let enumValue; if (isEnumType(enumType)) { enumValue = enumType.getValue(node.value); @@ -258,10 +256,13 @@ export class TypeInfo { switch (node.kind) { case Kind.SELECTION_SET: this._parentTypeStack.pop(); + break; case Kind.FIELD: this._fieldDefStack.pop(); + this._typeStack.pop(); + break; case Kind.DIRECTIVE: this._directive = null; @@ -270,19 +271,26 @@ export class TypeInfo { case Kind.INLINE_FRAGMENT: case Kind.FRAGMENT_DEFINITION: this._typeStack.pop(); + break; case Kind.VARIABLE_DEFINITION: this._inputTypeStack.pop(); + break; case Kind.ARGUMENT: this._argument = null; + this._defaultValueStack.pop(); + this._inputTypeStack.pop(); + break; case Kind.LIST: case Kind.OBJECT_FIELD: this._defaultValueStack.pop(); + this._inputTypeStack.pop(); + break; case Kind.ENUM: this._enumValue = null; @@ -300,7 +308,7 @@ function getFieldDef( schema: GraphQLSchema, parentType: GraphQLType, fieldNode: FieldNode, -): ?GraphQLField { +): GraphQLField | null | undefined { const name = fieldNode.name.value; if ( name === SchemaMetaFieldDef.name && @@ -330,7 +338,12 @@ export function visitWithTypeInfo( return { enter(node) { typeInfo.enter(node); - const fn = getVisitFn(visitor, node.kind, /* isLeaving */ false); + const fn = getVisitFn( + visitor, + node.kind, + /* isLeaving */ + false, + ); if (fn) { const result = fn.apply(visitor, arguments); if (result !== undefined) { @@ -343,7 +356,12 @@ export function visitWithTypeInfo( } }, leave(node) { - const fn = getVisitFn(visitor, node.kind, /* isLeaving */ true); + const fn = getVisitFn( + visitor, + node.kind, + /* isLeaving */ + true, + ); let result; if (fn) { result = fn.apply(visitor, arguments); diff --git a/src/utilities/__tests__/TypeInfo-test.js b/src/utilities/__tests__/TypeInfo-test.ts similarity index 100% rename from src/utilities/__tests__/TypeInfo-test.js rename to src/utilities/__tests__/TypeInfo-test.ts diff --git a/src/utilities/__tests__/assertValidName-test.js b/src/utilities/__tests__/assertValidName-test.ts similarity index 100% rename from src/utilities/__tests__/assertValidName-test.js rename to src/utilities/__tests__/assertValidName-test.ts diff --git a/src/utilities/__tests__/astFromValue-test.js b/src/utilities/__tests__/astFromValue-test.ts similarity index 100% rename from src/utilities/__tests__/astFromValue-test.js rename to src/utilities/__tests__/astFromValue-test.ts diff --git a/src/utilities/__tests__/buildASTSchema-test.js b/src/utilities/__tests__/buildASTSchema-test.ts similarity index 99% rename from src/utilities/__tests__/buildASTSchema-test.js rename to src/utilities/__tests__/buildASTSchema-test.ts index cb1794bd7af..31d3268fd4a 100644 --- a/src/utilities/__tests__/buildASTSchema-test.js +++ b/src/utilities/__tests__/buildASTSchema-test.ts @@ -5,12 +5,12 @@ import dedent from '../../__testUtils__/dedent'; import invariant from '../../jsutils/invariant'; -import type { ASTNode } from '../../language/ast'; +import { ASTNode } from '../../language/ast'; import { Kind } from '../../language/kinds'; import { parse } from '../../language/parser'; import { print } from '../../language/printer'; -import type { GraphQLNamedType } from '../../type/definition'; +import { GraphQLNamedType } from '../../type/definition'; import { GraphQLSchema } from '../../type/schema'; import { validateSchema } from '../../type/validate'; import { __Schema, __EnumValue } from '../../type/introspection'; @@ -51,7 +51,9 @@ function cycleSDL(sdl: string): string { return printSchema(buildSchema(sdl)); } -function printASTNode(obj: ?{ +astNode: ?ASTNode, ... }): string { +function printASTNode( + obj: { readonly astNode: ASTNode | null | undefined } | null | undefined, +): string { invariant(obj?.astNode != null); return print(obj.astNode); } diff --git a/src/utilities/__tests__/buildClientSchema-test.js b/src/utilities/__tests__/buildClientSchema-test.ts similarity index 96% rename from src/utilities/__tests__/buildClientSchema-test.js rename to src/utilities/__tests__/buildClientSchema-test.ts index 7be8a726409..d33095553de 100644 --- a/src/utilities/__tests__/buildClientSchema-test.js +++ b/src/utilities/__tests__/buildClientSchema-test.ts @@ -77,7 +77,7 @@ describe('Type System: build schema from introspection', () => { const schema = buildSchema(sdl); const introspection = introspectionFromSchema(schema); - delete (introspection: any).__schema.queryType; + delete (introspection as any).__schema.queryType; const clientSchema = buildClientSchema(introspection); expect(clientSchema.getQueryType()).to.equal(null); @@ -477,7 +477,7 @@ describe('Type System: build schema from introspection', () => { const schema = buildSchema(sdl); const introspection = introspectionFromSchema(schema); - delete (introspection: any).__schema.directives; + delete (introspection as any).__schema.directives; const clientSchema = buildClientSchema(introspection); @@ -611,7 +611,7 @@ describe('Type System: build schema from introspection', () => { it('throws when referenced unknown type', () => { const introspection = introspectionFromSchema(dummySchema); - (introspection: any).__schema.types = introspection.__schema.types.filter( + (introspection as any).__schema.types = introspection.__schema.types.filter( ({ name }) => name !== 'Query', ); @@ -628,7 +628,7 @@ describe('Type System: build schema from introspection', () => { `); const introspection = introspectionFromSchema(schema); - (introspection: any).__schema.types = introspection.__schema.types.filter( + (introspection as any).__schema.types = introspection.__schema.types.filter( ({ name }) => name !== 'Float', ); @@ -642,7 +642,7 @@ describe('Type System: build schema from introspection', () => { expect(introspection).to.have.nested.property('__schema.queryType.name'); - delete (introspection: any).__schema.queryType.name; + delete (introspection as any).__schema.queryType.name; expect(() => buildClientSchema(introspection)).to.throw( 'Unknown type reference: {}.', @@ -657,7 +657,7 @@ describe('Type System: build schema from introspection', () => { expect(queryTypeIntrospection).to.have.property('kind'); - delete (queryTypeIntrospection: any).kind; + delete (queryTypeIntrospection as any).kind; expect(() => buildClientSchema(introspection)).to.throw( /Invalid or incomplete introspection result. Ensure that a full introspection query is used in order to build a client schema: { name: "Query", .* }\./, @@ -672,7 +672,7 @@ describe('Type System: build schema from introspection', () => { expect(queryTypeIntrospection).to.have.property('interfaces'); - delete (queryTypeIntrospection: any).interfaces; + delete (queryTypeIntrospection as any).interfaces; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing interfaces: { kind: "OBJECT", name: "Query", .* }\./, @@ -686,7 +686,7 @@ describe('Type System: build schema from introspection', () => { ); expect(someInterfaceIntrospection).to.have.property('interfaces'); - (someInterfaceIntrospection: any).interfaces = null; + (someInterfaceIntrospection as any).interfaces = null; const clientSchema = buildClientSchema(introspection); expect(printSchema(clientSchema)).to.equal(printSchema(dummySchema)); @@ -699,7 +699,7 @@ describe('Type System: build schema from introspection', () => { ); expect(queryTypeIntrospection).to.have.property('fields'); - delete (queryTypeIntrospection: any).fields; + delete (queryTypeIntrospection as any).fields; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing fields: { kind: "OBJECT", name: "Query", .* }\./, @@ -713,7 +713,7 @@ describe('Type System: build schema from introspection', () => { ); expect(queryTypeIntrospection).to.have.nested.property('fields[0].args'); - delete (queryTypeIntrospection: any).fields[0].args; + delete (queryTypeIntrospection as any).fields[0].args; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing field args: { name: "foo", .* }\./, @@ -730,7 +730,7 @@ describe('Type System: build schema from introspection', () => { 'fields[0].args[0].type.name', 'String', ); - (queryTypeIntrospection: any).fields[0].args[0].type.name = 'SomeUnion'; + (queryTypeIntrospection as any).fields[0].args[0].type.name = 'SomeUnion'; expect(() => buildClientSchema(introspection)).to.throw( 'Introspection must provide input type for arguments, but received: SomeUnion.', @@ -747,7 +747,7 @@ describe('Type System: build schema from introspection', () => { 'fields[0].type.name', 'String', ); - (queryTypeIntrospection: any).fields[0].type.name = 'SomeInputObject'; + (queryTypeIntrospection as any).fields[0].type.name = 'SomeInputObject'; expect(() => buildClientSchema(introspection)).to.throw( 'Introspection must provide output type for fields, but received: SomeInputObject.', @@ -761,7 +761,7 @@ describe('Type System: build schema from introspection', () => { ); expect(someUnionIntrospection).to.have.property('possibleTypes'); - delete (someUnionIntrospection: any).possibleTypes; + delete (someUnionIntrospection as any).possibleTypes; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing possibleTypes: { kind: "UNION", name: "SomeUnion",.* }\./, @@ -775,7 +775,7 @@ describe('Type System: build schema from introspection', () => { ); expect(someEnumIntrospection).to.have.property('enumValues'); - delete (someEnumIntrospection: any).enumValues; + delete (someEnumIntrospection as any).enumValues; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing enumValues: { kind: "ENUM", name: "SomeEnum", .* }\./, @@ -789,7 +789,7 @@ describe('Type System: build schema from introspection', () => { ); expect(someInputObjectIntrospection).to.have.property('inputFields'); - delete (someInputObjectIntrospection: any).inputFields; + delete (someInputObjectIntrospection as any).inputFields; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing inputFields: { kind: "INPUT_OBJECT", name: "SomeInputObject", .* }\./, @@ -804,7 +804,7 @@ describe('Type System: build schema from introspection', () => { name: 'SomeDirective', locations: ['QUERY'], }); - delete (someDirectiveIntrospection: any).locations; + delete (someDirectiveIntrospection as any).locations; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing directive locations: { name: "SomeDirective", .* }\./, @@ -819,7 +819,7 @@ describe('Type System: build schema from introspection', () => { name: 'SomeDirective', args: [], }); - delete (someDirectiveIntrospection: any).args; + delete (someDirectiveIntrospection as any).args; expect(() => buildClientSchema(introspection)).to.throw( /Introspection result missing directive args: { name: "SomeDirective", .* }\./, diff --git a/src/utilities/__tests__/coerceInputValue-test.js b/src/utilities/__tests__/coerceInputValue-test.ts similarity index 98% rename from src/utilities/__tests__/coerceInputValue-test.js rename to src/utilities/__tests__/coerceInputValue-test.ts index 4da5636769c..f184d447050 100644 --- a/src/utilities/__tests__/coerceInputValue-test.js +++ b/src/utilities/__tests__/coerceInputValue-test.ts @@ -3,7 +3,7 @@ import { describe, it } from 'mocha'; import invariant from '../../jsutils/invariant'; -import type { GraphQLInputType } from '../../type/definition'; +import { GraphQLInputType } from '../../type/definition'; import { GraphQLInt } from '../../type/scalars'; import { GraphQLList, @@ -25,7 +25,7 @@ function expectErrors(result: any) { } describe('coerceInputValue', () => { - function coerceValue(inputValue: mixed, type: GraphQLInputType) { + function coerceValue(inputValue: unknown, type: GraphQLInputType) { const errors = []; const value = coerceInputValue( inputValue, diff --git a/src/utilities/__tests__/concatAST-test.js b/src/utilities/__tests__/concatAST-test.ts similarity index 100% rename from src/utilities/__tests__/concatAST-test.js rename to src/utilities/__tests__/concatAST-test.ts diff --git a/src/utilities/__tests__/extendSchema-test.js b/src/utilities/__tests__/extendSchema-test.ts similarity index 99% rename from src/utilities/__tests__/extendSchema-test.js rename to src/utilities/__tests__/extendSchema-test.ts index 64ac885c4bd..675486109b9 100644 --- a/src/utilities/__tests__/extendSchema-test.js +++ b/src/utilities/__tests__/extendSchema-test.ts @@ -5,14 +5,14 @@ import dedent from '../../__testUtils__/dedent'; import invariant from '../../jsutils/invariant'; -import type { ASTNode } from '../../language/ast'; +import { ASTNode } from '../../language/ast'; import { Kind } from '../../language/kinds'; import { parse } from '../../language/parser'; import { print } from '../../language/printer'; import { graphqlSync } from '../../graphql'; -import type { GraphQLNamedType } from '../../type/definition'; +import { GraphQLNamedType } from '../../type/definition'; import { GraphQLSchema } from '../../type/schema'; import { validateSchema } from '../../type/validate'; import { assertDirective } from '../../type/directives'; @@ -37,7 +37,9 @@ import { printSchema } from '../printSchema'; import { extendSchema } from '../extendSchema'; import { buildSchema } from '../buildASTSchema'; -function printExtensionNodes(obj: ?GraphQLNamedType | GraphQLSchema): string { +function printExtensionNodes( + obj: (GraphQLNamedType | null | undefined) | GraphQLSchema, +): string { invariant(obj?.extensionASTNodes != null); return print({ kind: Kind.DOCUMENT, @@ -59,7 +61,9 @@ function printSchemaChanges( }); } -function printASTNode(obj: ?{ +astNode: ?ASTNode, ... }): string { +function printASTNode( + obj: { readonly astNode: ASTNode | null | undefined } | null | undefined, +): string { invariant(obj?.astNode != null); return print(obj.astNode); } diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.ts similarity index 100% rename from src/utilities/__tests__/findBreakingChanges-test.js rename to src/utilities/__tests__/findBreakingChanges-test.ts diff --git a/src/utilities/__tests__/getIntrospectionQuery-test.js b/src/utilities/__tests__/getIntrospectionQuery-test.ts similarity index 100% rename from src/utilities/__tests__/getIntrospectionQuery-test.js rename to src/utilities/__tests__/getIntrospectionQuery-test.ts diff --git a/src/utilities/__tests__/getOperationAST-test.js b/src/utilities/__tests__/getOperationAST-test.ts similarity index 100% rename from src/utilities/__tests__/getOperationAST-test.js rename to src/utilities/__tests__/getOperationAST-test.ts diff --git a/src/utilities/__tests__/getOperationRootType-test.js b/src/utilities/__tests__/getOperationRootType-test.ts similarity index 98% rename from src/utilities/__tests__/getOperationRootType-test.js rename to src/utilities/__tests__/getOperationRootType-test.ts index 8ebdcdfd8b0..b2b3b7a87df 100644 --- a/src/utilities/__tests__/getOperationRootType-test.js +++ b/src/utilities/__tests__/getOperationRootType-test.ts @@ -3,7 +3,7 @@ import { describe, it } from 'mocha'; import invariant from '../../jsutils/invariant'; -import type { DocumentNode } from '../../language/ast'; +import { DocumentNode } from '../../language/ast'; import { Kind } from '../../language/kinds'; import { parse } from '../../language/parser'; diff --git a/src/utilities/__tests__/introspectionFromSchema-test.js b/src/utilities/__tests__/introspectionFromSchema-test.ts similarity index 95% rename from src/utilities/__tests__/introspectionFromSchema-test.js rename to src/utilities/__tests__/introspectionFromSchema-test.ts index 2aacbfce2b6..bd31296ab15 100644 --- a/src/utilities/__tests__/introspectionFromSchema-test.js +++ b/src/utilities/__tests__/introspectionFromSchema-test.ts @@ -7,7 +7,7 @@ import { GraphQLSchema } from '../../type/schema'; import { GraphQLString } from '../../type/scalars'; import { GraphQLObjectType } from '../../type/definition'; -import type { IntrospectionQuery } from '../getIntrospectionQuery'; +import { IntrospectionQuery } from '../getIntrospectionQuery'; import { printSchema } from '../printSchema'; import { buildClientSchema } from '../buildClientSchema'; import { introspectionFromSchema } from '../introspectionFromSchema'; diff --git a/src/utilities/__tests__/lexicographicSortSchema-test.js b/src/utilities/__tests__/lexicographicSortSchema-test.ts similarity index 100% rename from src/utilities/__tests__/lexicographicSortSchema-test.js rename to src/utilities/__tests__/lexicographicSortSchema-test.ts diff --git a/src/utilities/__tests__/printSchema-test.js b/src/utilities/__tests__/printSchema-test.ts similarity index 99% rename from src/utilities/__tests__/printSchema-test.js rename to src/utilities/__tests__/printSchema-test.ts index 2bedc1478fb..7d20534f2f2 100644 --- a/src/utilities/__tests__/printSchema-test.js +++ b/src/utilities/__tests__/printSchema-test.ts @@ -5,7 +5,7 @@ import dedent from '../../__testUtils__/dedent'; import { DirectiveLocation } from '../../language/directiveLocation'; -import type { GraphQLFieldConfig } from '../../type/definition'; +import { GraphQLFieldConfig } from '../../type/definition'; import { GraphQLSchema } from '../../type/schema'; import { GraphQLDirective } from '../../type/directives'; import { GraphQLInt, GraphQLString, GraphQLBoolean } from '../../type/scalars'; @@ -30,7 +30,9 @@ function expectPrintedSchema(schema: GraphQLSchema) { return expect(schemaText); } -function buildSingleFieldSchema(fieldConfig: GraphQLFieldConfig) { +function buildSingleFieldSchema( + fieldConfig: GraphQLFieldConfig, +) { const Query = new GraphQLObjectType({ name: 'Query', fields: { singleField: fieldConfig }, diff --git a/src/utilities/__tests__/separateOperations-test.js b/src/utilities/__tests__/separateOperations-test.ts similarity index 100% rename from src/utilities/__tests__/separateOperations-test.js rename to src/utilities/__tests__/separateOperations-test.ts diff --git a/src/utilities/__tests__/stripIgnoredCharacters-fuzz.js b/src/utilities/__tests__/stripIgnoredCharacters-fuzz.ts similarity index 100% rename from src/utilities/__tests__/stripIgnoredCharacters-fuzz.js rename to src/utilities/__tests__/stripIgnoredCharacters-fuzz.ts diff --git a/src/utilities/__tests__/stripIgnoredCharacters-test.js b/src/utilities/__tests__/stripIgnoredCharacters-test.ts similarity index 99% rename from src/utilities/__tests__/stripIgnoredCharacters-test.js rename to src/utilities/__tests__/stripIgnoredCharacters-test.ts index fdc7d907d66..6bad509e85f 100644 --- a/src/utilities/__tests__/stripIgnoredCharacters-test.js +++ b/src/utilities/__tests__/stripIgnoredCharacters-test.ts @@ -17,19 +17,15 @@ import { stripIgnoredCharacters } from '../stripIgnoredCharacters'; const ignoredTokens = [ // UnicodeBOM :: '\uFEFF', // Byte Order Mark (U+FEFF) - // WhiteSpace :: '\t', // Horizontal Tab (U+0009) ' ', // Space (U+0020) - // LineTerminator :: '\n', // "New Line (U+000A)" '\r', // "Carriage Return (U+000D)" [ lookahead ! "New Line (U+000A)" ] '\r\n', // "Carriage Return (U+000D)" "New Line (U+000A)" - // Comment :: '# "Comment" string\n', // `#` CommentChar* - // Comma :: ',', // , ]; @@ -58,7 +54,7 @@ const nonPunctuatorTokens = [ '"""block\nstring\nvalue"""', // StringValue(BlockString) ]; -function lexValue(str: string): ?string { +function lexValue(str: string): string | null | undefined { const lexer = new Lexer(new Source(str)); const value = lexer.advance().value; diff --git a/src/utilities/__tests__/typeComparators-test.js b/src/utilities/__tests__/typeComparators-test.ts similarity index 97% rename from src/utilities/__tests__/typeComparators-test.js rename to src/utilities/__tests__/typeComparators-test.ts index 3f2a87ae780..0a3f1adfa0d 100644 --- a/src/utilities/__tests__/typeComparators-test.js +++ b/src/utilities/__tests__/typeComparators-test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import type { GraphQLFieldConfigMap } from '../../type/definition'; +import { GraphQLFieldConfigMap } from '../../type/definition'; import { GraphQLSchema } from '../../type/schema'; import { GraphQLString, GraphQLInt, GraphQLFloat } from '../../type/scalars'; import { @@ -53,7 +53,7 @@ describe('typeComparators', () => { }); describe('isTypeSubTypeOf', () => { - function testSchema(fields: GraphQLFieldConfigMap) { + function testSchema(fields: GraphQLFieldConfigMap) { return new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', diff --git a/src/utilities/__tests__/valueFromAST-test.js b/src/utilities/__tests__/valueFromAST-test.ts similarity index 98% rename from src/utilities/__tests__/valueFromAST-test.js rename to src/utilities/__tests__/valueFromAST-test.ts index f4dc325206b..5bfef80230f 100644 --- a/src/utilities/__tests__/valueFromAST-test.js +++ b/src/utilities/__tests__/valueFromAST-test.ts @@ -1,13 +1,13 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import type { ObjMap } from '../../jsutils/ObjMap'; +import { ObjMap } from '../../jsutils/ObjMap'; import invariant from '../../jsutils/invariant'; import identityFunc from '../../jsutils/identityFunc'; import { parseValue } from '../../language/parser'; -import type { GraphQLInputType } from '../../type/definition'; +import { GraphQLInputType } from '../../type/definition'; import { GraphQLInt, GraphQLFloat, @@ -29,7 +29,7 @@ describe('valueFromAST', () => { function expectValueFrom( valueText: string, type: GraphQLInputType, - variables: ?ObjMap, + variables: ObjMap | null | undefined, ) { const ast = parseValue(valueText); const value = valueFromAST(ast, type, variables); diff --git a/src/utilities/__tests__/valueFromASTUntyped-test.js b/src/utilities/__tests__/valueFromASTUntyped-test.ts similarity index 93% rename from src/utilities/__tests__/valueFromASTUntyped-test.js rename to src/utilities/__tests__/valueFromASTUntyped-test.ts index 5e971a43f61..3eb79104c02 100644 --- a/src/utilities/__tests__/valueFromASTUntyped-test.js +++ b/src/utilities/__tests__/valueFromASTUntyped-test.ts @@ -1,14 +1,17 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import type { ObjMap } from '../../jsutils/ObjMap'; +import { ObjMap } from '../../jsutils/ObjMap'; import { parseValue } from '../../language/parser'; import { valueFromASTUntyped } from '../valueFromASTUntyped'; describe('valueFromASTUntyped', () => { - function expectValueFrom(valueText: string, variables?: ?ObjMap) { + function expectValueFrom( + valueText: string, + variables?: ObjMap | null | undefined, + ) { const ast = parseValue(valueText); const value = valueFromASTUntyped(ast, variables); return expect(value); diff --git a/src/utilities/assertValidName.js b/src/utilities/assertValidName.ts similarity index 100% rename from src/utilities/assertValidName.js rename to src/utilities/assertValidName.ts diff --git a/src/utilities/astFromValue.js b/src/utilities/astFromValue.ts similarity index 94% rename from src/utilities/astFromValue.js rename to src/utilities/astFromValue.ts index da5ad950518..4a57672141b 100644 --- a/src/utilities/astFromValue.js +++ b/src/utilities/astFromValue.ts @@ -5,10 +5,10 @@ import invariant from '../jsutils/invariant'; import isObjectLike from '../jsutils/isObjectLike'; import isCollection from '../jsutils/isCollection'; -import type { ValueNode } from '../language/ast'; +import { ValueNode } from '../language/ast'; import { Kind } from '../language/kinds'; -import type { GraphQLInputType } from '../type/definition'; +import { GraphQLInputType } from '../type/definition'; import { GraphQLID } from '../type/scalars'; import { isLeafType, @@ -39,7 +39,10 @@ import { * | null | NullValue | * */ -export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { +export function astFromValue( + value: unknown, + type: GraphQLInputType, +): ValueNode | null | undefined { if (isNonNullType(type)) { const astValue = astFromValue(value, type.ofType); if (astValue?.kind === Kind.NULL) { @@ -140,7 +143,7 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { } // istanbul ignore next (Not reachable. All possible input types have been considered) - invariant(false, 'Unexpected input type: ' + inspect((type: empty))); + invariant(false, 'Unexpected input type: ' + inspect(type as never)); } /** diff --git a/src/utilities/buildASTSchema.js b/src/utilities/buildASTSchema.ts similarity index 83% rename from src/utilities/buildASTSchema.js rename to src/utilities/buildASTSchema.ts index 7f72cb61143..fe3584920cb 100644 --- a/src/utilities/buildASTSchema.js +++ b/src/utilities/buildASTSchema.ts @@ -1,29 +1,27 @@ import devAssert from '../jsutils/devAssert'; -import type { Source } from '../language/source'; -import type { DocumentNode } from '../language/ast'; -import type { ParseOptions } from '../language/parser'; +import { Source } from '../language/source'; +import { DocumentNode } from '../language/ast'; +import { ParseOptions } from '../language/parser'; import { Kind } from '../language/kinds'; import { parse } from '../language/parser'; import { assertValidSDL } from '../validation/validate'; -import type { GraphQLSchemaValidationOptions } from '../type/schema'; +import { GraphQLSchemaValidationOptions } from '../type/schema'; import { GraphQLSchema } from '../type/schema'; import { specifiedDirectives } from '../type/directives'; import { extendSchemaImpl } from './extendSchema'; -export type BuildSchemaOptions = {| - ...GraphQLSchemaValidationOptions, - +export type BuildSchemaOptions = GraphQLSchemaValidationOptions & { /** * Set to true to assume the SDL is valid. * * Default: false */ - assumeValidSDL?: boolean, -|}; + assumeValidSDL?: boolean; +}; /** * This takes the ast of a schema document produced by the parse function in @@ -65,13 +63,13 @@ export function buildASTSchema( // typed values below, that would throw immediately while type system // validation with validateSchema() will produce more actionable results. case 'Query': - config.query = (type: any); + config.query = type as any; break; case 'Mutation': - config.mutation = (type: any); + config.mutation = type as any; break; case 'Subscription': - config.subscription = (type: any); + config.subscription = type as any; break; } } @@ -94,7 +92,7 @@ export function buildASTSchema( */ export function buildSchema( source: string | Source, - options?: {| ...BuildSchemaOptions, ...ParseOptions |}, + options?: BuildSchemaOptions & ParseOptions, ): GraphQLSchema { const document = parse(source, { noLocation: options?.noLocation, diff --git a/src/utilities/buildClientSchema.js b/src/utilities/buildClientSchema.ts similarity index 98% rename from src/utilities/buildClientSchema.js rename to src/utilities/buildClientSchema.ts index 59498e849bf..2a7925dd059 100644 --- a/src/utilities/buildClientSchema.js +++ b/src/utilities/buildClientSchema.ts @@ -7,8 +7,8 @@ import isObjectLike from '../jsutils/isObjectLike'; import { parseValue } from '../language/parser'; -import type { GraphQLSchemaValidationOptions } from '../type/schema'; -import type { +import { GraphQLSchemaValidationOptions } from '../type/schema'; +import { GraphQLType, GraphQLNamedType, GraphQLFieldConfig, @@ -34,7 +34,7 @@ import { assertInterfaceType, } from '../type/definition'; -import type { +import { IntrospectionQuery, IntrospectionDirective, IntrospectionField, @@ -310,7 +310,7 @@ export function buildClientSchema( function buildFieldDefMap( typeIntrospection: IntrospectionObjectType | IntrospectionInterfaceType, - ): GraphQLFieldConfigMap { + ): GraphQLFieldConfigMap { if (!typeIntrospection.fields) { throw new Error( `Introspection result missing fields: ${inspect(typeIntrospection)}.`, @@ -326,7 +326,7 @@ export function buildClientSchema( function buildField( fieldIntrospection: IntrospectionField, - ): GraphQLFieldConfig { + ): GraphQLFieldConfig { const type = getType(fieldIntrospection.type); if (!isOutputType(type)) { const typeStr = inspect(type); @@ -351,7 +351,7 @@ export function buildClientSchema( } function buildInputValueDefMap( - inputValueIntrospections: $ReadOnlyArray, + inputValueIntrospections: ReadonlyArray, ) { return keyValMap( inputValueIntrospections, diff --git a/src/utilities/coerceInputValue.js b/src/utilities/coerceInputValue.ts similarity index 92% rename from src/utilities/coerceInputValue.js rename to src/utilities/coerceInputValue.ts index e7b40e952e1..c409a827e14 100644 --- a/src/utilities/coerceInputValue.js +++ b/src/utilities/coerceInputValue.ts @@ -1,6 +1,6 @@ import objectValues from '../polyfills/objectValues'; -import type { Path } from '../jsutils/Path'; +import { Path } from '../jsutils/Path'; import inspect from '../jsutils/inspect'; import invariant from '../jsutils/invariant'; import didYouMean from '../jsutils/didYouMean'; @@ -12,7 +12,7 @@ import { addPath, pathToArray } from '../jsutils/Path'; import { GraphQLError } from '../error/GraphQLError'; -import type { GraphQLInputType } from '../type/definition'; +import { GraphQLInputType } from '../type/definition'; import { isLeafType, isInputObjectType, @@ -21,8 +21,8 @@ import { } from '../type/definition'; type OnErrorCB = ( - path: $ReadOnlyArray, - invalidValue: mixed, + path: ReadonlyArray, + invalidValue: unknown, error: GraphQLError, ) => void; @@ -30,16 +30,16 @@ type OnErrorCB = ( * Coerces a JavaScript value given a GraphQL Input Type. */ export function coerceInputValue( - inputValue: mixed, + inputValue: unknown, type: GraphQLInputType, - onError?: OnErrorCB = defaultOnError, -): mixed { + onError: OnErrorCB = defaultOnError, +): unknown { return coerceInputValueImpl(inputValue, type, onError); } function defaultOnError( - path: $ReadOnlyArray, - invalidValue: mixed, + path: ReadonlyArray, + invalidValue: unknown, error: GraphQLError, ): void { let errorPrefix = 'Invalid value ' + inspect(invalidValue); @@ -51,11 +51,11 @@ function defaultOnError( } function coerceInputValueImpl( - inputValue: mixed, + inputValue: unknown, type: GraphQLInputType, onError: OnErrorCB, path: Path | void, -): mixed { +): unknown { if (isNonNullType(type)) { if (inputValue != null) { return coerceInputValueImpl(inputValue, type.ofType, onError, path); @@ -186,5 +186,5 @@ function coerceInputValueImpl( } // istanbul ignore next (Not reachable. All possible input types have been considered) - invariant(false, 'Unexpected input type: ' + inspect((type: empty))); + invariant(false, 'Unexpected input type: ' + inspect(type as never)); } diff --git a/src/utilities/concatAST.js b/src/utilities/concatAST.ts similarity index 82% rename from src/utilities/concatAST.js rename to src/utilities/concatAST.ts index b7a0ea47266..074d6c5a4ca 100644 --- a/src/utilities/concatAST.js +++ b/src/utilities/concatAST.ts @@ -1,4 +1,4 @@ -import type { DocumentNode } from '../language/ast'; +import { DocumentNode } from '../language/ast'; /** * Provided a collection of ASTs, presumably each from different files, @@ -6,7 +6,7 @@ import type { DocumentNode } from '../language/ast'; * GraphQL source files which together represent one conceptual application. */ export function concatAST( - documents: $ReadOnlyArray, + documents: ReadonlyArray, ): DocumentNode { let definitions = []; for (const doc of documents) { diff --git a/src/utilities/extendSchema.js b/src/utilities/extendSchema.ts similarity index 91% rename from src/utilities/extendSchema.js rename to src/utilities/extendSchema.ts index 5bdf49e03b5..7feb6d6bdfe 100644 --- a/src/utilities/extendSchema.js +++ b/src/utilities/extendSchema.ts @@ -6,8 +6,8 @@ import mapValue from '../jsutils/mapValue'; import invariant from '../jsutils/invariant'; import devAssert from '../jsutils/devAssert'; -import type { DirectiveLocationEnum } from '../language/directiveLocation'; -import type { +import { DirectiveLocationEnum } from '../language/directiveLocation'; +import { DocumentNode, TypeNode, NamedTypeNode, @@ -41,11 +41,11 @@ import { assertValidSDLExtension } from '../validation/validate'; import { getDirectiveValues } from '../execution/values'; -import type { +import { GraphQLSchemaValidationOptions, GraphQLSchemaNormalizedConfig, } from '../type/schema'; -import type { +import { GraphQLType, GraphQLNamedType, GraphQLFieldConfig, @@ -84,16 +84,14 @@ import { import { valueFromAST } from './valueFromAST'; -type Options = {| - ...GraphQLSchemaValidationOptions, - +type Options = GraphQLSchemaValidationOptions & { /** * Set to true to assume the SDL is valid. * * Default: false */ - assumeValidSDL?: boolean, -|}; + assumeValidSDL?: boolean; +}; /** * Produces a new schema given an existing schema and a document which may @@ -146,7 +144,7 @@ export function extendSchemaImpl( // have the same name. For example, a type named "skip". const directiveDefs: Array = []; - let schemaDef: ?SchemaDefinitionNode; + let schemaDef: SchemaDefinitionNode | null | undefined; // Schema extensions are collected which may add additional operation types. const schemaExtensions: Array = []; @@ -219,7 +217,7 @@ export function extendSchemaImpl( // Below are functions used for producing this schema that have closed over // this scope and have access to the schema, cache, and newly defined types. - function replaceType(type: T): T { + function replaceType(type: T): T { if (isListType(type)) { // $FlowFixMe[incompatible-return] return new GraphQLList(replaceType(type.ofType)); @@ -231,11 +229,11 @@ export function extendSchemaImpl( return replaceNamedType(type); } - function replaceNamedType(type: T): T { + function replaceNamedType(type: T): T { // Note: While this could make early assertions to get the correctly // typed values, that would throw immediately while type system // validation with validateSchema() will produce more actionable results. - return ((typeMap[type.name]: any): T); + return (typeMap[type.name] as any) as T; } function replaceDirective(directive: GraphQLDirective): GraphQLDirective { @@ -272,7 +270,7 @@ export function extendSchemaImpl( } // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false, 'Unexpected type: ' + inspect((type: empty))); + invariant(false, 'Unexpected type: ' + inspect(type as never)); } function extendInputObjectType( @@ -377,8 +375,8 @@ export function extendSchemaImpl( } function extendField( - field: GraphQLFieldConfig, - ): GraphQLFieldConfig { + field: GraphQLFieldConfig, + ): GraphQLFieldConfig { return { ...field, type: replaceType(field.type), @@ -395,12 +393,12 @@ export function extendSchemaImpl( } function getOperationTypes( - nodes: $ReadOnlyArray, - ): {| - query: ?GraphQLObjectType, - mutation: ?GraphQLObjectType, - subscription: ?GraphQLObjectType, - |} { + nodes: ReadonlyArray, + ): { + query: GraphQLObjectType | null | undefined; + mutation: GraphQLObjectType | null | undefined; + subscription: GraphQLObjectType | null | undefined; + } { const opTypes = {}; for (const node of nodes) { // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') @@ -414,7 +412,7 @@ export function extendSchemaImpl( // Note: While this could make early assertions to get the correctly // typed values below, that would throw immediately while type system // validation with validateSchema() will produce more actionable results. - return (opTypes: any); + return opTypes as any; } function getNamedType(node: NamedTypeNode): GraphQLNamedType { @@ -440,7 +438,7 @@ export function extendSchemaImpl( function buildDirective(node: DirectiveDefinitionNode): GraphQLDirective { const locations = node.locations.map( - ({ value }) => ((value: any): DirectiveLocationEnum), + ({ value }) => (value as any) as DirectiveLocationEnum, ); return new GraphQLDirective({ @@ -454,13 +452,13 @@ export function extendSchemaImpl( } function buildFieldMap( - nodes: $ReadOnlyArray< + nodes: ReadonlyArray< | InterfaceTypeDefinitionNode | InterfaceTypeExtensionNode | ObjectTypeDefinitionNode - | ObjectTypeExtensionNode, + | ObjectTypeExtensionNode >, - ): GraphQLFieldConfigMap { + ): GraphQLFieldConfigMap { const fieldConfigMap = Object.create(null); for (const node of nodes) { // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') @@ -471,7 +469,7 @@ export function extendSchemaImpl( // Note: While this could make assertions to get the correctly typed // value, that would throw immediately while type system validation // with validateSchema() will produce more actionable results. - type: (getWrappedType(field.type): any), + type: getWrappedType(field.type) as any, description: field.description?.value, args: buildArgumentMap(field.arguments), deprecationReason: getDeprecationReason(field), @@ -483,7 +481,7 @@ export function extendSchemaImpl( } function buildArgumentMap( - args: ?$ReadOnlyArray, + args: ReadonlyArray | null | undefined, ): GraphQLFieldConfigArgumentMap { // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') const argsNodes = args ?? []; @@ -507,8 +505,8 @@ export function extendSchemaImpl( } function buildInputFieldMap( - nodes: $ReadOnlyArray< - InputObjectTypeDefinitionNode | InputObjectTypeExtensionNode, + nodes: ReadonlyArray< + InputObjectTypeDefinitionNode | InputObjectTypeExtensionNode >, ): GraphQLInputFieldConfigMap { const inputFieldMap = Object.create(null); @@ -535,7 +533,7 @@ export function extendSchemaImpl( } function buildEnumValueMap( - nodes: $ReadOnlyArray, + nodes: ReadonlyArray, ): GraphQLEnumValueConfigMap { const enumValueMap = Object.create(null); for (const node of nodes) { @@ -554,11 +552,11 @@ export function extendSchemaImpl( } function buildInterfaces( - nodes: $ReadOnlyArray< + nodes: ReadonlyArray< | InterfaceTypeDefinitionNode | InterfaceTypeExtensionNode | ObjectTypeDefinitionNode - | ObjectTypeExtensionNode, + | ObjectTypeExtensionNode >, ): Array { const interfaces = []; @@ -571,14 +569,14 @@ export function extendSchemaImpl( // values below, that would throw immediately while type system // validation with validateSchema() will produce more actionable // results. - interfaces.push((getNamedType(type): any)); + interfaces.push(getNamedType(type) as any); } } return interfaces; } function buildUnionTypes( - nodes: $ReadOnlyArray, + nodes: ReadonlyArray, ): Array { const types = []; for (const node of nodes) { @@ -590,7 +588,7 @@ export function extendSchemaImpl( // values below, that would throw immediately while type system // validation with validateSchema() will produce more actionable // results. - types.push((getNamedType(type): any)); + types.push(getNamedType(type) as any); } } return types; @@ -602,7 +600,7 @@ export function extendSchemaImpl( switch (astNode.kind) { case Kind.OBJECT_TYPE_DEFINITION: { - const extensionASTNodes = (extensionNodes: any); + const extensionASTNodes = extensionNodes as any; const allNodes = [astNode, ...extensionASTNodes]; return new GraphQLObjectType({ @@ -615,7 +613,7 @@ export function extendSchemaImpl( }); } case Kind.INTERFACE_TYPE_DEFINITION: { - const extensionASTNodes = (extensionNodes: any); + const extensionASTNodes = extensionNodes as any; const allNodes = [astNode, ...extensionASTNodes]; return new GraphQLInterfaceType({ @@ -628,7 +626,7 @@ export function extendSchemaImpl( }); } case Kind.ENUM_TYPE_DEFINITION: { - const extensionASTNodes = (extensionNodes: any); + const extensionASTNodes = extensionNodes as any; const allNodes = [astNode, ...extensionASTNodes]; return new GraphQLEnumType({ @@ -640,7 +638,7 @@ export function extendSchemaImpl( }); } case Kind.UNION_TYPE_DEFINITION: { - const extensionASTNodes = (extensionNodes: any); + const extensionASTNodes = extensionNodes as any; const allNodes = [astNode, ...extensionASTNodes]; return new GraphQLUnionType({ @@ -652,7 +650,7 @@ export function extendSchemaImpl( }); } case Kind.SCALAR_TYPE_DEFINITION: { - const extensionASTNodes = (extensionNodes: any); + const extensionASTNodes = extensionNodes as any; return new GraphQLScalarType({ name, @@ -663,7 +661,7 @@ export function extendSchemaImpl( }); } case Kind.INPUT_OBJECT_TYPE_DEFINITION: { - const extensionASTNodes = (extensionNodes: any); + const extensionASTNodes = extensionNodes as any; const allNodes = [astNode, ...extensionASTNodes]; return new GraphQLInputObjectType({ @@ -679,7 +677,7 @@ export function extendSchemaImpl( // istanbul ignore next (Not reachable. All possible type definition nodes have been considered) invariant( false, - 'Unexpected type definition node: ' + inspect((astNode: empty)), + 'Unexpected type definition node: ' + inspect(astNode as never), ); } } @@ -698,9 +696,9 @@ function getDeprecationReason( | EnumValueDefinitionNode | FieldDefinitionNode | InputValueDefinitionNode, -): ?string { +): string | null | undefined { const deprecated = getDirectiveValues(GraphQLDeprecatedDirective, node); - return (deprecated?.reason: any); + return deprecated?.reason as any; } /** @@ -708,7 +706,7 @@ function getDeprecationReason( */ function getSpecifiedByUrl( node: ScalarTypeDefinitionNode | ScalarTypeExtensionNode, -): ?string { +): string | null | undefined { const specifiedBy = getDirectiveValues(GraphQLSpecifiedByDirective, node); - return (specifiedBy?.url: any); + return specifiedBy?.url as any; } diff --git a/src/utilities/findBreakingChanges.js b/src/utilities/findBreakingChanges.ts similarity index 93% rename from src/utilities/findBreakingChanges.js rename to src/utilities/findBreakingChanges.ts index 999f93feb91..9bf90fc4106 100644 --- a/src/utilities/findBreakingChanges.js +++ b/src/utilities/findBreakingChanges.ts @@ -1,3 +1,4 @@ +import { $Keys } from 'utility-types'; import objectValues from '../polyfills/objectValues'; import keyMap from '../jsutils/keyMap'; @@ -7,8 +8,8 @@ import invariant from '../jsutils/invariant'; import { print } from '../language/printer'; import { visit } from '../language/visitor'; -import type { GraphQLSchema } from '../type/schema'; -import type { +import { GraphQLSchema } from '../type/schema'; +import { GraphQLField, GraphQLType, GraphQLInputType, @@ -64,15 +65,15 @@ export const DangerousChangeType = Object.freeze({ ARG_DEFAULT_VALUE_CHANGE: 'ARG_DEFAULT_VALUE_CHANGE', }); -export type BreakingChange = {| - type: $Keys, - description: string, -|}; +export type BreakingChange = { + type: $Keys; + description: string; +}; -export type DangerousChange = {| - type: $Keys, - description: string, -|}; +export type DangerousChange = { + type: $Keys; + description: string; +}; /** * Given two schemas, returns an Array containing descriptions of all the types @@ -85,7 +86,7 @@ export function findBreakingChanges( const breakingChanges = findSchemaChanges(oldSchema, newSchema).filter( (change) => change.type in BreakingChangeType, ); - return ((breakingChanges: any): Array); + return (breakingChanges as any) as Array; } /** @@ -99,7 +100,7 @@ export function findDangerousChanges( const dangerousChanges = findSchemaChanges(oldSchema, newSchema).filter( (change) => change.type in DangerousChangeType, ); - return ((dangerousChanges: any): Array); + return (dangerousChanges as any) as Array; } function findSchemaChanges( @@ -379,8 +380,8 @@ function findFieldChanges( function findArgChanges( oldType: GraphQLObjectType | GraphQLInterfaceType, - oldField: GraphQLField, - newField: GraphQLField, + oldField: GraphQLField, + newField: GraphQLField, ): Array { const schemaChanges = []; const argsDiff = diff(oldField.args, newField.args); @@ -455,8 +456,7 @@ function isChangeSafeForObjectOrInterfaceField( isChangeSafeForObjectOrInterfaceField( oldType.ofType, newType.ofType, - )) || - // moving from nullable to non-null of the same underlying type is safe + )) || // moving from nullable to non-null of the same underlying type is safe (isNonNullType(newType) && isChangeSafeForObjectOrInterfaceField(oldType, newType.ofType)) ); @@ -472,8 +472,7 @@ function isChangeSafeForObjectOrInterfaceField( return ( // if they're both named types, see if their names are equivalent - (isNamedType(newType) && oldType.name === newType.name) || - // moving from nullable to non-null of the same underlying type is safe + (isNamedType(newType) && oldType.name === newType.name) || // moving from nullable to non-null of the same underlying type is safe (isNonNullType(newType) && isChangeSafeForObjectOrInterfaceField(oldType, newType.ofType)) ); @@ -499,8 +498,7 @@ function isChangeSafeForInputObjectFieldOrFieldArg( isChangeSafeForInputObjectFieldOrFieldArg( oldType.ofType, newType.ofType, - )) || - // moving from non-null to nullable of the same underlying type is safe + )) || // moving from non-null to nullable of the same underlying type is safe (!isNonNullType(newType) && isChangeSafeForInputObjectFieldOrFieldArg(oldType.ofType, newType)) ); @@ -532,10 +530,10 @@ function typeKindName(type: GraphQLNamedType): string { } // istanbul ignore next (Not reachable. All possible named types have been considered) - invariant(false, 'Unexpected type: ' + inspect((type: empty))); + invariant(false, 'Unexpected type: ' + inspect(type as never)); } -function stringifyValue(value: mixed, type: GraphQLInputType): string { +function stringifyValue(value: unknown, type: GraphQLInputType): string { const ast = astFromValue(value, type); invariant(ast != null); @@ -551,14 +549,14 @@ function stringifyValue(value: mixed, type: GraphQLInputType): string { return print(sortedAST); } -function diff( - oldArray: $ReadOnlyArray, - newArray: $ReadOnlyArray, -): {| - added: Array, - removed: Array, - persisted: Array<[T, T]>, -|} { +function diff( + oldArray: ReadonlyArray, + newArray: ReadonlyArray, +): { + added: Array; + removed: Array; + persisted: Array<[T, T]>; +} { const added = []; const removed = []; const persisted = []; diff --git a/src/utilities/getIntrospectionQuery.js b/src/utilities/getIntrospectionQuery.js deleted file mode 100644 index d54e77e510c..00000000000 --- a/src/utilities/getIntrospectionQuery.js +++ /dev/null @@ -1,298 +0,0 @@ -import type { DirectiveLocationEnum } from '../language/directiveLocation'; - -export type IntrospectionOptions = {| - // Whether to include descriptions in the introspection result. - // Default: true - descriptions?: boolean, - - // Whether to include `specifiedByUrl` in the introspection result. - // Default: false - specifiedByUrl?: boolean, - - // Whether to include `isRepeatable` field on directives. - // Default: false - directiveIsRepeatable?: boolean, - - // Whether to include `description` field on schema. - // Default: false - schemaDescription?: boolean, -|}; - -export function getIntrospectionQuery(options?: IntrospectionOptions): string { - const optionsWithDefault = { - descriptions: true, - specifiedByUrl: false, - directiveIsRepeatable: false, - schemaDescription: false, - ...options, - }; - - const descriptions = optionsWithDefault.descriptions ? 'description' : ''; - const specifiedByUrl = optionsWithDefault.specifiedByUrl - ? 'specifiedByUrl' - : ''; - const directiveIsRepeatable = optionsWithDefault.directiveIsRepeatable - ? 'isRepeatable' - : ''; - const schemaDescription = optionsWithDefault.schemaDescription - ? descriptions - : ''; - - return ` - query IntrospectionQuery { - __schema { - ${schemaDescription} - queryType { name } - mutationType { name } - subscriptionType { name } - types { - ...FullType - } - directives { - name - ${descriptions} - ${directiveIsRepeatable} - locations - args { - ...InputValue - } - } - } - } - - fragment FullType on __Type { - kind - name - ${descriptions} - ${specifiedByUrl} - fields(includeDeprecated: true) { - name - ${descriptions} - args { - ...InputValue - } - type { - ...TypeRef - } - isDeprecated - deprecationReason - } - inputFields { - ...InputValue - } - interfaces { - ...TypeRef - } - enumValues(includeDeprecated: true) { - name - ${descriptions} - isDeprecated - deprecationReason - } - possibleTypes { - ...TypeRef - } - } - - fragment InputValue on __InputValue { - name - ${descriptions} - type { ...TypeRef } - defaultValue - } - - fragment TypeRef on __Type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - `; -} - -export type IntrospectionQuery = {| - +__schema: IntrospectionSchema, -|}; - -export type IntrospectionSchema = {| - +description?: ?string, - +queryType: IntrospectionNamedTypeRef, - +mutationType: ?IntrospectionNamedTypeRef, - +subscriptionType: ?IntrospectionNamedTypeRef, - +types: $ReadOnlyArray, - +directives: $ReadOnlyArray, -|}; - -export type IntrospectionType = - | IntrospectionScalarType - | IntrospectionObjectType - | IntrospectionInterfaceType - | IntrospectionUnionType - | IntrospectionEnumType - | IntrospectionInputObjectType; - -export type IntrospectionOutputType = - | IntrospectionScalarType - | IntrospectionObjectType - | IntrospectionInterfaceType - | IntrospectionUnionType - | IntrospectionEnumType; - -export type IntrospectionInputType = - | IntrospectionScalarType - | IntrospectionEnumType - | IntrospectionInputObjectType; - -export type IntrospectionScalarType = {| - +kind: 'SCALAR', - +name: string, - +description?: ?string, - +specifiedByUrl?: ?string, -|}; - -export type IntrospectionObjectType = {| - +kind: 'OBJECT', - +name: string, - +description?: ?string, - +fields: $ReadOnlyArray, - +interfaces: $ReadOnlyArray< - IntrospectionNamedTypeRef, - >, -|}; - -export type IntrospectionInterfaceType = {| - +kind: 'INTERFACE', - +name: string, - +description?: ?string, - +fields: $ReadOnlyArray, - +interfaces: $ReadOnlyArray< - IntrospectionNamedTypeRef, - >, - +possibleTypes: $ReadOnlyArray< - IntrospectionNamedTypeRef, - >, -|}; - -export type IntrospectionUnionType = {| - +kind: 'UNION', - +name: string, - +description?: ?string, - +possibleTypes: $ReadOnlyArray< - IntrospectionNamedTypeRef, - >, -|}; - -export type IntrospectionEnumType = {| - +kind: 'ENUM', - +name: string, - +description?: ?string, - +enumValues: $ReadOnlyArray, -|}; - -export type IntrospectionInputObjectType = {| - +kind: 'INPUT_OBJECT', - +name: string, - +description?: ?string, - +inputFields: $ReadOnlyArray, -|}; - -export type IntrospectionListTypeRef< - T: IntrospectionTypeRef = IntrospectionTypeRef, -> = {| - +kind: 'LIST', - +ofType: T, -|}; - -export type IntrospectionNonNullTypeRef< - T: IntrospectionTypeRef = IntrospectionTypeRef, -> = {| - +kind: 'NON_NULL', - +ofType: T, -|}; - -export type IntrospectionTypeRef = - | IntrospectionNamedTypeRef<> - | IntrospectionListTypeRef<> - | IntrospectionNonNullTypeRef< - IntrospectionNamedTypeRef<> | IntrospectionListTypeRef<>, - >; - -export type IntrospectionOutputTypeRef = - | IntrospectionNamedTypeRef - | IntrospectionListTypeRef - | IntrospectionNonNullTypeRef< - | IntrospectionNamedTypeRef - | IntrospectionListTypeRef, - >; - -export type IntrospectionInputTypeRef = - | IntrospectionNamedTypeRef - | IntrospectionListTypeRef - | IntrospectionNonNullTypeRef< - | IntrospectionNamedTypeRef - | IntrospectionListTypeRef, - >; - -export type IntrospectionNamedTypeRef< - T: IntrospectionType = IntrospectionType, -> = {| - +kind: $PropertyType, - +name: string, -|}; - -export type IntrospectionField = {| - +name: string, - +description?: ?string, - +args: $ReadOnlyArray, - +type: IntrospectionOutputTypeRef, - +isDeprecated: boolean, - +deprecationReason: ?string, -|}; - -export type IntrospectionInputValue = {| - +name: string, - +description?: ?string, - +type: IntrospectionInputTypeRef, - +defaultValue: ?string, -|}; - -export type IntrospectionEnumValue = {| - +name: string, - +description?: ?string, - +isDeprecated: boolean, - +deprecationReason: ?string, -|}; - -export type IntrospectionDirective = {| - +name: string, - +description?: ?string, - +isRepeatable?: boolean, - +locations: $ReadOnlyArray, - +args: $ReadOnlyArray, -|}; diff --git a/src/utilities/getIntrospectionQuery.ts b/src/utilities/getIntrospectionQuery.ts new file mode 100644 index 00000000000..db9eb613b7f --- /dev/null +++ b/src/utilities/getIntrospectionQuery.ts @@ -0,0 +1,305 @@ +import { $PropertyType } from 'utility-types'; +import { DirectiveLocationEnum } from '../language/directiveLocation'; + +export type IntrospectionOptions = { + // Whether to include descriptions in the introspection result. + // Default: true + descriptions?: boolean; + + // Whether to include `specifiedByUrl` in the introspection result. + // Default: false + specifiedByUrl?: boolean; + + // Whether to include `isRepeatable` field on directives. + // Default: false + directiveIsRepeatable?: boolean; + + // Whether to include `description` field on schema. + // Default: false + schemaDescription?: boolean; +}; + +export function getIntrospectionQuery(options?: IntrospectionOptions): string { + const optionsWithDefault = { + descriptions: true, + specifiedByUrl: false, + directiveIsRepeatable: false, + schemaDescription: false, + ...options, + }; + + const descriptions = optionsWithDefault.descriptions ? 'description' : ''; + const specifiedByUrl = optionsWithDefault.specifiedByUrl + ? 'specifiedByUrl' + : ''; + const directiveIsRepeatable = optionsWithDefault.directiveIsRepeatable + ? 'isRepeatable' + : ''; + const schemaDescription = optionsWithDefault.schemaDescription + ? descriptions + : ''; + + return ` + query IntrospectionQuery { + __schema { + ${schemaDescription} + queryType { name } + mutationType { name } + subscriptionType { name } + types { + ...FullType + } + directives { + name + ${descriptions} + ${directiveIsRepeatable} + locations + args { + ...InputValue + } + } + } + } + + fragment FullType on __Type { + kind + name + ${descriptions} + ${specifiedByUrl} + fields(includeDeprecated: true) { + name + ${descriptions} + args { + ...InputValue + } + type { + ...TypeRef + } + isDeprecated + deprecationReason + } + inputFields { + ...InputValue + } + interfaces { + ...TypeRef + } + enumValues(includeDeprecated: true) { + name + ${descriptions} + isDeprecated + deprecationReason + } + possibleTypes { + ...TypeRef + } + } + + fragment InputValue on __InputValue { + name + ${descriptions} + type { ...TypeRef } + defaultValue + } + + fragment TypeRef on __Type { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + } + } + } + } + } + } + } + } + `; +} + +export type IntrospectionQuery = { + readonly __schema: IntrospectionSchema; +}; + +export type IntrospectionSchema = { + readonly description?: string | null | undefined; + readonly queryType: IntrospectionNamedTypeRef; + readonly mutationType: + | IntrospectionNamedTypeRef + | null + | undefined; + readonly subscriptionType: + | IntrospectionNamedTypeRef + | null + | undefined; + readonly types: ReadonlyArray; + readonly directives: ReadonlyArray; +}; + +export type IntrospectionType = + | IntrospectionScalarType + | IntrospectionObjectType + | IntrospectionInterfaceType + | IntrospectionUnionType + | IntrospectionEnumType + | IntrospectionInputObjectType; + +export type IntrospectionOutputType = + | IntrospectionScalarType + | IntrospectionObjectType + | IntrospectionInterfaceType + | IntrospectionUnionType + | IntrospectionEnumType; + +export type IntrospectionInputType = + | IntrospectionScalarType + | IntrospectionEnumType + | IntrospectionInputObjectType; + +export type IntrospectionScalarType = { + readonly kind: 'SCALAR'; + readonly name: string; + readonly description?: string | null | undefined; + readonly specifiedByUrl?: string | null | undefined; +}; + +export type IntrospectionObjectType = { + readonly kind: 'OBJECT'; + readonly name: string; + readonly description?: string | null | undefined; + readonly fields: ReadonlyArray; + readonly interfaces: ReadonlyArray< + IntrospectionNamedTypeRef + >; +}; + +export type IntrospectionInterfaceType = { + readonly kind: 'INTERFACE'; + readonly name: string; + readonly description?: string | null | undefined; + readonly fields: ReadonlyArray; + readonly interfaces: ReadonlyArray< + IntrospectionNamedTypeRef + >; + readonly possibleTypes: ReadonlyArray< + IntrospectionNamedTypeRef + >; +}; + +export type IntrospectionUnionType = { + readonly kind: 'UNION'; + readonly name: string; + readonly description?: string | null | undefined; + readonly possibleTypes: ReadonlyArray< + IntrospectionNamedTypeRef + >; +}; + +export type IntrospectionEnumType = { + readonly kind: 'ENUM'; + readonly name: string; + readonly description?: string | null | undefined; + readonly enumValues: ReadonlyArray; +}; + +export type IntrospectionInputObjectType = { + readonly kind: 'INPUT_OBJECT'; + readonly name: string; + readonly description?: string | null | undefined; + readonly inputFields: ReadonlyArray; +}; + +export type IntrospectionListTypeRef< + T extends IntrospectionTypeRef = IntrospectionTypeRef +> = { + readonly kind: 'LIST'; + readonly ofType: T; +}; + +export type IntrospectionNonNullTypeRef< + T extends IntrospectionTypeRef = IntrospectionTypeRef +> = { + readonly kind: 'NON_NULL'; + readonly ofType: T; +}; + +export type IntrospectionTypeRef = + | IntrospectionNamedTypeRef<> + | IntrospectionListTypeRef<> + | IntrospectionNonNullTypeRef< + IntrospectionNamedTypeRef<> | IntrospectionListTypeRef<> + >; + +export type IntrospectionOutputTypeRef = + | IntrospectionNamedTypeRef + | IntrospectionListTypeRef + | IntrospectionNonNullTypeRef< + | IntrospectionNamedTypeRef + | IntrospectionListTypeRef + >; + +export type IntrospectionInputTypeRef = + | IntrospectionNamedTypeRef + | IntrospectionListTypeRef + | IntrospectionNonNullTypeRef< + | IntrospectionNamedTypeRef + | IntrospectionListTypeRef + >; + +export type IntrospectionNamedTypeRef< + T extends IntrospectionType = IntrospectionType +> = { + readonly kind: $PropertyType; + readonly name: string; +}; + +export type IntrospectionField = { + readonly name: string; + readonly description?: string | null | undefined; + readonly args: ReadonlyArray; + readonly type: IntrospectionOutputTypeRef; + readonly isDeprecated: boolean; + readonly deprecationReason: string | null | undefined; +}; + +export type IntrospectionInputValue = { + readonly name: string; + readonly description?: string | null | undefined; + readonly type: IntrospectionInputTypeRef; + readonly defaultValue: string | null | undefined; +}; + +export type IntrospectionEnumValue = { + readonly name: string; + readonly description?: string | null | undefined; + readonly isDeprecated: boolean; + readonly deprecationReason: string | null | undefined; +}; + +export type IntrospectionDirective = { + readonly name: string; + readonly description?: string | null | undefined; + readonly isRepeatable?: boolean; + readonly locations: ReadonlyArray; + readonly args: ReadonlyArray; +}; diff --git a/src/utilities/getOperationAST.js b/src/utilities/getOperationAST.ts similarity index 83% rename from src/utilities/getOperationAST.js rename to src/utilities/getOperationAST.ts index 259d2f05c56..31a448dc474 100644 --- a/src/utilities/getOperationAST.js +++ b/src/utilities/getOperationAST.ts @@ -1,4 +1,4 @@ -import type { DocumentNode, OperationDefinitionNode } from '../language/ast'; +import { DocumentNode, OperationDefinitionNode } from '../language/ast'; import { Kind } from '../language/kinds'; /** @@ -8,8 +8,8 @@ import { Kind } from '../language/kinds'; */ export function getOperationAST( documentAST: DocumentNode, - operationName?: ?string, -): ?OperationDefinitionNode { + operationName?: string | null | undefined, +): OperationDefinitionNode | null | undefined { let operation = null; for (const definition of documentAST.definitions) { if (definition.kind === Kind.OPERATION_DEFINITION) { diff --git a/src/utilities/getOperationRootType.js b/src/utilities/getOperationRootType.ts similarity index 90% rename from src/utilities/getOperationRootType.js rename to src/utilities/getOperationRootType.ts index 039cefaa409..b9a94436cd7 100644 --- a/src/utilities/getOperationRootType.js +++ b/src/utilities/getOperationRootType.ts @@ -1,12 +1,12 @@ import { GraphQLError } from '../error/GraphQLError'; -import type { +import { OperationDefinitionNode, OperationTypeDefinitionNode, } from '../language/ast'; -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLObjectType } from '../type/definition'; +import { GraphQLSchema } from '../type/schema'; +import { GraphQLObjectType } from '../type/definition'; /** * Extracts the root type of the operation from the schema. diff --git a/src/utilities/index.js b/src/utilities/index.ts similarity index 95% rename from src/utilities/index.js rename to src/utilities/index.ts index b4c8372f04e..49addf3e4e4 100644 --- a/src/utilities/index.js +++ b/src/utilities/index.ts @@ -2,7 +2,7 @@ // Accepts optional IntrospectionOptions. export { getIntrospectionQuery } from './getIntrospectionQuery'; -export type { +export { IntrospectionOptions, IntrospectionQuery, IntrospectionSchema, @@ -41,7 +41,7 @@ export { buildClientSchema } from './buildClientSchema'; // Build a GraphQLSchema from GraphQL Schema language. export { buildASTSchema, buildSchema } from './buildASTSchema'; -export type { BuildSchemaOptions } from './buildASTSchema'; +export { BuildSchemaOptions } from './buildASTSchema'; // Extends an existing GraphQLSchema from a parsed GraphQL Schema language AST. export { extendSchema } from './extendSchema'; @@ -102,4 +102,4 @@ export { findBreakingChanges, findDangerousChanges, } from './findBreakingChanges'; -export type { BreakingChange, DangerousChange } from './findBreakingChanges'; +export { BreakingChange, DangerousChange } from './findBreakingChanges'; diff --git a/src/utilities/introspectionFromSchema.js b/src/utilities/introspectionFromSchema.ts similarity index 91% rename from src/utilities/introspectionFromSchema.js rename to src/utilities/introspectionFromSchema.ts index e880b82995d..613dbed46a0 100644 --- a/src/utilities/introspectionFromSchema.js +++ b/src/utilities/introspectionFromSchema.ts @@ -2,11 +2,11 @@ import invariant from '../jsutils/invariant'; import { parse } from '../language/parser'; -import type { GraphQLSchema } from '../type/schema'; +import { GraphQLSchema } from '../type/schema'; import { executeSync } from '../execution/execute'; -import type { +import { IntrospectionQuery, IntrospectionOptions, } from './getIntrospectionQuery'; @@ -34,5 +34,5 @@ export function introspectionFromSchema( const document = parse(getIntrospectionQuery(optionsWithDefaults)); const result = executeSync({ schema, document }); invariant(!result.errors && result.data); - return (result.data: any); + return result.data as any; } diff --git a/src/utilities/lexicographicSortSchema.js b/src/utilities/lexicographicSortSchema.ts similarity index 84% rename from src/utilities/lexicographicSortSchema.js rename to src/utilities/lexicographicSortSchema.ts index 57cbff0c482..8e63e78db11 100644 --- a/src/utilities/lexicographicSortSchema.js +++ b/src/utilities/lexicographicSortSchema.ts @@ -1,11 +1,11 @@ import objectValues from '../polyfills/objectValues'; -import type { ObjMap } from '../jsutils/ObjMap'; +import { ObjMap } from '../jsutils/ObjMap'; import inspect from '../jsutils/inspect'; import invariant from '../jsutils/invariant'; import keyValMap from '../jsutils/keyValMap'; -import type { +import { GraphQLType, GraphQLNamedType, GraphQLFieldConfigMap, @@ -55,7 +55,7 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { subscription: replaceMaybeType(schemaConfig.subscription), }); - function replaceType(type: T): T { + function replaceType(type: T): T { if (isListType(type)) { // $FlowFixMe[incompatible-return] return new GraphQLList(replaceType(type.ofType)); @@ -66,11 +66,13 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { return replaceNamedType(type); } - function replaceNamedType(type: T): T { - return ((typeMap[type.name]: any): T); + function replaceNamedType(type: T): T { + return (typeMap[type.name] as any) as T; } - function replaceMaybeType(maybeType: T): T { + function replaceMaybeType( + maybeType: T, + ): T { return maybeType && replaceNamedType(maybeType); } @@ -90,7 +92,7 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { })); } - function sortFields(fieldsMap: GraphQLFieldConfigMap) { + function sortFields(fieldsMap: GraphQLFieldConfigMap) { return sortObjMap(fieldsMap, (field) => ({ ...field, type: replaceType(field.type), @@ -105,11 +107,13 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { })); } - function sortTypes(arr: $ReadOnlyArray): Array { + function sortTypes( + arr: ReadonlyArray, + ): Array { return sortByName(arr).map(replaceNamedType); } - function sortNamedType(type: T) { + function sortNamedType(type: T) { if (isScalarType(type) || isIntrospectionType(type)) { return type; } @@ -153,11 +157,14 @@ export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema { } // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false, 'Unexpected type: ' + inspect((type: empty))); + invariant(false, 'Unexpected type: ' + inspect(type as never)); } } -function sortObjMap(map: ObjMap, sortValueFn?: (T) => R): ObjMap { +function sortObjMap( + map: ObjMap, + sortValueFn?: (arg0: T) => R, +): ObjMap { const sortedMap = Object.create(null); const sortedKeys = sortBy(Object.keys(map), (x) => x); for (const key of sortedKeys) { @@ -167,15 +174,15 @@ function sortObjMap(map: ObjMap, sortValueFn?: (T) => R): ObjMap { return sortedMap; } -function sortByName( - array: $ReadOnlyArray, +function sortByName( + array: ReadonlyArray, ): Array { return sortBy(array, (obj) => obj.name); } function sortBy( - array: $ReadOnlyArray, - mapToKey: (T) => string, + array: ReadonlyArray, + mapToKey: (arg0: T) => string, ): Array { return array.slice().sort((obj1, obj2) => { const key1 = mapToKey(obj1); diff --git a/src/utilities/printSchema.js b/src/utilities/printSchema.ts similarity index 94% rename from src/utilities/printSchema.js rename to src/utilities/printSchema.ts index 2d02ef6fd1e..b1dfab460f5 100644 --- a/src/utilities/printSchema.js +++ b/src/utilities/printSchema.ts @@ -6,9 +6,9 @@ import invariant from '../jsutils/invariant'; import { print } from '../language/printer'; import { printBlockString } from '../language/blockString'; -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLDirective } from '../type/directives'; -import type { +import { GraphQLSchema } from '../type/schema'; +import { GraphQLDirective } from '../type/directives'; +import { GraphQLNamedType, GraphQLArgument, GraphQLInputField, @@ -71,7 +71,9 @@ function printFilteredSchema( ); } -function printSchemaDefinition(schema: GraphQLSchema): ?string { +function printSchemaDefinition( + schema: GraphQLSchema, +): string | null | undefined { if (schema.description == null && isSchemaOfCommonNames(schema)) { return; } @@ -149,7 +151,7 @@ export function printType(type: GraphQLNamedType): string { } // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false, 'Unexpected type: ' + inspect((type: empty))); + invariant(false, 'Unexpected type: ' + inspect(type as never)); } function printScalar(type: GraphQLScalarType): string { @@ -226,7 +228,7 @@ function printFields(type: GraphQLObjectType | GraphQLInterfaceType): string { return printBlock(fields); } -function printBlock(items: $ReadOnlyArray): string { +function printBlock(items: ReadonlyArray): string { return items.length !== 0 ? ' {\n' + items.join('\n') + '\n}' : ''; } @@ -281,7 +283,7 @@ function printDirective(directive: GraphQLDirective): string { ); } -function printDeprecated(reason: ?string): string { +function printDeprecated(reason: string | null | undefined): string { if (reason == null) { return ''; } @@ -306,7 +308,7 @@ function printSpecifiedByUrl(scalar: GraphQLScalarType): string { } function printDescription( - def: { +description: ?string, ... }, + def: { readonly description: string | null | undefined }, indentation: string = '', firstInBlock: boolean = true, ): string { diff --git a/src/utilities/separateOperations.js b/src/utilities/separateOperations.ts similarity index 95% rename from src/utilities/separateOperations.js rename to src/utilities/separateOperations.ts index f7be8f5cb94..e4e9fb9f7cd 100644 --- a/src/utilities/separateOperations.js +++ b/src/utilities/separateOperations.ts @@ -1,6 +1,6 @@ -import type { ObjMap } from '../jsutils/ObjMap'; +import { ObjMap } from '../jsutils/ObjMap'; -import type { DocumentNode, OperationDefinitionNode } from '../language/ast'; +import { DocumentNode, OperationDefinitionNode } from '../language/ast'; import { Kind } from '../language/kinds'; import { visit } from '../language/visitor'; diff --git a/src/utilities/stripIgnoredCharacters.js b/src/utilities/stripIgnoredCharacters.ts similarity index 100% rename from src/utilities/stripIgnoredCharacters.js rename to src/utilities/stripIgnoredCharacters.ts diff --git a/src/utilities/typeComparators.js b/src/utilities/typeComparators.ts similarity index 96% rename from src/utilities/typeComparators.js rename to src/utilities/typeComparators.ts index 99f84d2e7a3..eb088da3d06 100644 --- a/src/utilities/typeComparators.js +++ b/src/utilities/typeComparators.ts @@ -1,5 +1,5 @@ -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLType, GraphQLCompositeType } from '../type/definition'; +import { GraphQLSchema } from '../type/schema'; +import { GraphQLType, GraphQLCompositeType } from '../type/definition'; import { isInterfaceType, isObjectType, diff --git a/src/utilities/typeFromAST.js b/src/utilities/typeFromAST.ts similarity index 85% rename from src/utilities/typeFromAST.js rename to src/utilities/typeFromAST.ts index 6903c5287af..44ccc1c2556 100644 --- a/src/utilities/typeFromAST.js +++ b/src/utilities/typeFromAST.ts @@ -1,16 +1,12 @@ import inspect from '../jsutils/inspect'; import invariant from '../jsutils/invariant'; -import type { - NamedTypeNode, - ListTypeNode, - NonNullTypeNode, -} from '../language/ast'; +import { NamedTypeNode, ListTypeNode, NonNullTypeNode } from '../language/ast'; import { Kind } from '../language/kinds'; -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLNamedType } from '../type/definition'; +import { GraphQLSchema } from '../type/schema'; +import { GraphQLNamedType } from '../type/definition'; import { GraphQLList, GraphQLNonNull } from '../type/definition'; /** @@ -20,6 +16,7 @@ import { GraphQLList, GraphQLNonNull } from '../type/definition'; * the type called "User" found in the schema. If a type called "User" is not * found in the schema, then undefined will be returned. */ + /* eslint-disable no-redeclare */ declare function typeFromAST( schema: GraphQLSchema, @@ -50,5 +47,5 @@ export function typeFromAST(schema, typeNode) { } // istanbul ignore next (Not reachable. All possible type nodes have been considered) - invariant(false, 'Unexpected type node: ' + inspect((typeNode: empty))); + invariant(false, 'Unexpected type node: ' + inspect(typeNode as never)); } diff --git a/src/utilities/valueFromAST.js b/src/utilities/valueFromAST.ts similarity index 93% rename from src/utilities/valueFromAST.js rename to src/utilities/valueFromAST.ts index 7afed422820..cb5c08bb220 100644 --- a/src/utilities/valueFromAST.js +++ b/src/utilities/valueFromAST.ts @@ -1,14 +1,14 @@ import objectValues from '../polyfills/objectValues'; -import type { ObjMap } from '../jsutils/ObjMap'; +import { ObjMap } from '../jsutils/ObjMap'; import keyMap from '../jsutils/keyMap'; import inspect from '../jsutils/inspect'; import invariant from '../jsutils/invariant'; -import type { ValueNode } from '../language/ast'; +import { ValueNode } from '../language/ast'; import { Kind } from '../language/kinds'; -import type { GraphQLInputType } from '../type/definition'; +import { GraphQLInputType } from '../type/definition'; import { isLeafType, isInputObjectType, @@ -37,10 +37,10 @@ import { * */ export function valueFromAST( - valueNode: ?ValueNode, + valueNode: ValueNode | null | undefined, type: GraphQLInputType, - variables?: ?ObjMap, -): mixed | void { + variables?: ObjMap | null | undefined, +): unknown | void { if (!valueNode) { // When there is no node, then there is also no value. // Importantly, this is different from returning the value null. @@ -147,14 +147,14 @@ export function valueFromAST( } // istanbul ignore next (Not reachable. All possible input types have been considered) - invariant(false, 'Unexpected input type: ' + inspect((type: empty))); + invariant(false, 'Unexpected input type: ' + inspect(type as never)); } // Returns true if the provided valueNode is a variable which is not defined // in the set of variables. function isMissingVariable( valueNode: ValueNode, - variables: ?ObjMap, + variables: ObjMap | null | undefined, ): boolean { return ( valueNode.kind === Kind.VARIABLE && diff --git a/src/utilities/valueFromASTUntyped.js b/src/utilities/valueFromASTUntyped.ts similarity index 87% rename from src/utilities/valueFromASTUntyped.js rename to src/utilities/valueFromASTUntyped.ts index 3b70329bda1..5ac30981348 100644 --- a/src/utilities/valueFromASTUntyped.js +++ b/src/utilities/valueFromASTUntyped.ts @@ -1,10 +1,10 @@ -import type { ObjMap } from '../jsutils/ObjMap'; +import { ObjMap } from '../jsutils/ObjMap'; import inspect from '../jsutils/inspect'; import invariant from '../jsutils/invariant'; import keyValMap from '../jsutils/keyValMap'; import { Kind } from '../language/kinds'; -import type { ValueNode } from '../language/ast'; +import { ValueNode } from '../language/ast'; /** * Produces a JavaScript value given a GraphQL Value AST. @@ -24,8 +24,8 @@ import type { ValueNode } from '../language/ast'; */ export function valueFromASTUntyped( valueNode: ValueNode, - variables?: ?ObjMap, -): mixed { + variables?: ObjMap | null | undefined, +): unknown { switch (valueNode.kind) { case Kind.NULL: return null; @@ -52,5 +52,5 @@ export function valueFromASTUntyped( } // istanbul ignore next (Not reachable. All possible value nodes have been considered) - invariant(false, 'Unexpected value node: ' + inspect((valueNode: empty))); + invariant(false, 'Unexpected value node: ' + inspect(valueNode as never)); } diff --git a/src/validation/ValidationContext.js b/src/validation/ValidationContext.ts similarity index 75% rename from src/validation/ValidationContext.js rename to src/validation/ValidationContext.ts index 9bb3dbab6bb..97cf6e443f7 100644 --- a/src/validation/ValidationContext.js +++ b/src/validation/ValidationContext.ts @@ -1,9 +1,9 @@ -import type { ObjMap } from '../jsutils/ObjMap'; +import { ObjMap } from '../jsutils/ObjMap'; -import type { GraphQLError } from '../error/GraphQLError'; +import { GraphQLError } from '../error/GraphQLError'; -import type { ASTVisitor } from '../language/visitor'; -import type { +import { ASTVisitor } from '../language/visitor'; +import { DocumentNode, OperationDefinitionNode, VariableNode, @@ -15,9 +15,9 @@ import type { import { Kind } from '../language/kinds'; import { visit } from '../language/visitor'; -import type { GraphQLSchema } from '../type/schema'; -import type { GraphQLDirective } from '../type/directives'; -import type { +import { GraphQLSchema } from '../type/schema'; +import { GraphQLDirective } from '../type/directives'; +import { GraphQLInputType, GraphQLOutputType, GraphQLCompositeType, @@ -29,11 +29,11 @@ import type { import { TypeInfo, visitWithTypeInfo } from '../utilities/TypeInfo'; type NodeWithSelectionSet = OperationDefinitionNode | FragmentDefinitionNode; -type VariableUsage = {| - +node: VariableNode, - +type: ?GraphQLInputType, - +defaultValue: ?mixed, -|}; +type VariableUsage = { + readonly node: VariableNode; + readonly type: GraphQLInputType | null | undefined; + readonly defaultValue: unknown | null | undefined; +}; /** * An instance of this class is passed as the "this" context to all validators, @@ -43,11 +43,11 @@ type VariableUsage = {| export class ASTValidationContext { _ast: DocumentNode; _onError: (err: GraphQLError) => void; - _fragments: ?ObjMap; - _fragmentSpreads: Map>; + _fragments: ObjMap | null | undefined; + _fragmentSpreads: Map>; _recursivelyReferencedFragments: Map< OperationDefinitionNode, - $ReadOnlyArray, + ReadonlyArray >; constructor(ast: DocumentNode, onError: (err: GraphQLError) => void): void { @@ -66,7 +66,7 @@ export class ASTValidationContext { return this._ast; } - getFragment(name: string): ?FragmentDefinitionNode { + getFragment(name: string): FragmentDefinitionNode | null | undefined { let fragments = this._fragments; if (!fragments) { this._fragments = fragments = this.getDocument().definitions.reduce( @@ -84,7 +84,7 @@ export class ASTValidationContext { getFragmentSpreads( node: SelectionSetNode, - ): $ReadOnlyArray { + ): ReadonlyArray { let spreads = this._fragmentSpreads.get(node); if (!spreads) { spreads = []; @@ -106,7 +106,7 @@ export class ASTValidationContext { getRecursivelyReferencedFragments( operation: OperationDefinitionNode, - ): $ReadOnlyArray { + ): ReadonlyArray { let fragments = this._recursivelyReferencedFragments.get(operation); if (!fragments) { fragments = []; @@ -132,34 +132,34 @@ export class ASTValidationContext { } } -export type ASTValidationRule = (ASTValidationContext) => ASTVisitor; +export type ASTValidationRule = (arg0: ASTValidationContext) => ASTVisitor; export class SDLValidationContext extends ASTValidationContext { - _schema: ?GraphQLSchema; + _schema: GraphQLSchema | null | undefined; constructor( ast: DocumentNode, - schema: ?GraphQLSchema, + schema: GraphQLSchema | null | undefined, onError: (err: GraphQLError) => void, ): void { super(ast, onError); this._schema = schema; } - getSchema(): ?GraphQLSchema { + getSchema(): GraphQLSchema | null | undefined { return this._schema; } } -export type SDLValidationRule = (SDLValidationContext) => ASTVisitor; +export type SDLValidationRule = (arg0: SDLValidationContext) => ASTVisitor; export class ValidationContext extends ASTValidationContext { _schema: GraphQLSchema; _typeInfo: TypeInfo; - _variableUsages: Map>; + _variableUsages: Map>; _recursiveVariableUsages: Map< OperationDefinitionNode, - $ReadOnlyArray, + ReadonlyArray >; constructor( @@ -179,7 +179,7 @@ export class ValidationContext extends ASTValidationContext { return this._schema; } - getVariableUsages(node: NodeWithSelectionSet): $ReadOnlyArray { + getVariableUsages(node: NodeWithSelectionSet): ReadonlyArray { let usages = this._variableUsages.get(node); if (!usages) { const newUsages = []; @@ -205,7 +205,7 @@ export class ValidationContext extends ASTValidationContext { getRecursiveVariableUsages( operation: OperationDefinitionNode, - ): $ReadOnlyArray { + ): ReadonlyArray { let usages = this._recursiveVariableUsages.get(operation); if (!usages) { usages = this.getVariableUsages(operation); @@ -217,37 +217,37 @@ export class ValidationContext extends ASTValidationContext { return usages; } - getType(): ?GraphQLOutputType { + getType(): GraphQLOutputType | null | undefined { return this._typeInfo.getType(); } - getParentType(): ?GraphQLCompositeType { + getParentType(): GraphQLCompositeType | null | undefined { return this._typeInfo.getParentType(); } - getInputType(): ?GraphQLInputType { + getInputType(): GraphQLInputType | null | undefined { return this._typeInfo.getInputType(); } - getParentInputType(): ?GraphQLInputType { + getParentInputType(): GraphQLInputType | null | undefined { return this._typeInfo.getParentInputType(); } - getFieldDef(): ?GraphQLField { + getFieldDef(): GraphQLField | null | undefined { return this._typeInfo.getFieldDef(); } - getDirective(): ?GraphQLDirective { + getDirective(): GraphQLDirective | null | undefined { return this._typeInfo.getDirective(); } - getArgument(): ?GraphQLArgument { + getArgument(): GraphQLArgument | null | undefined { return this._typeInfo.getArgument(); } - getEnumValue(): ?GraphQLEnumValue { + getEnumValue(): GraphQLEnumValue | null | undefined { return this._typeInfo.getEnumValue(); } } -export type ValidationRule = (ValidationContext) => ASTVisitor; +export type ValidationRule = (arg0: ValidationContext) => ASTVisitor; diff --git a/src/validation/__tests__/ExecutableDefinitionsRule-test.js b/src/validation/__tests__/ExecutableDefinitionsRule-test.ts similarity index 100% rename from src/validation/__tests__/ExecutableDefinitionsRule-test.js rename to src/validation/__tests__/ExecutableDefinitionsRule-test.ts diff --git a/src/validation/__tests__/FieldsOnCorrectTypeRule-test.js b/src/validation/__tests__/FieldsOnCorrectTypeRule-test.ts similarity index 99% rename from src/validation/__tests__/FieldsOnCorrectTypeRule-test.js rename to src/validation/__tests__/FieldsOnCorrectTypeRule-test.ts index 6ec857a683c..6ea5893e55c 100644 --- a/src/validation/__tests__/FieldsOnCorrectTypeRule-test.js +++ b/src/validation/__tests__/FieldsOnCorrectTypeRule-test.ts @@ -3,7 +3,7 @@ import { describe, it } from 'mocha'; import { parse } from '../../language/parser'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; diff --git a/src/validation/__tests__/FragmentsOnCompositeTypesRule-test.js b/src/validation/__tests__/FragmentsOnCompositeTypesRule-test.ts similarity index 100% rename from src/validation/__tests__/FragmentsOnCompositeTypesRule-test.js rename to src/validation/__tests__/FragmentsOnCompositeTypesRule-test.ts diff --git a/src/validation/__tests__/KnownArgumentNamesRule-test.js b/src/validation/__tests__/KnownArgumentNamesRule-test.ts similarity index 99% rename from src/validation/__tests__/KnownArgumentNamesRule-test.js rename to src/validation/__tests__/KnownArgumentNamesRule-test.ts index 8bf7567c506..3ba96e7b49b 100644 --- a/src/validation/__tests__/KnownArgumentNamesRule-test.js +++ b/src/validation/__tests__/KnownArgumentNamesRule-test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'mocha'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; diff --git a/src/validation/__tests__/KnownDirectivesRule-test.js b/src/validation/__tests__/KnownDirectivesRule-test.ts similarity index 99% rename from src/validation/__tests__/KnownDirectivesRule-test.js rename to src/validation/__tests__/KnownDirectivesRule-test.ts index 13491bc6c5a..8af53915b51 100644 --- a/src/validation/__tests__/KnownDirectivesRule-test.js +++ b/src/validation/__tests__/KnownDirectivesRule-test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'mocha'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; diff --git a/src/validation/__tests__/KnownFragmentNamesRule-test.js b/src/validation/__tests__/KnownFragmentNamesRule-test.ts similarity index 100% rename from src/validation/__tests__/KnownFragmentNamesRule-test.js rename to src/validation/__tests__/KnownFragmentNamesRule-test.ts diff --git a/src/validation/__tests__/KnownTypeNamesRule-test.js b/src/validation/__tests__/KnownTypeNamesRule-test.ts similarity index 99% rename from src/validation/__tests__/KnownTypeNamesRule-test.js rename to src/validation/__tests__/KnownTypeNamesRule-test.ts index f56ef4ceab5..24885709251 100644 --- a/src/validation/__tests__/KnownTypeNamesRule-test.js +++ b/src/validation/__tests__/KnownTypeNamesRule-test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'mocha'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; diff --git a/src/validation/__tests__/LoneAnonymousOperationRule-test.js b/src/validation/__tests__/LoneAnonymousOperationRule-test.ts similarity index 100% rename from src/validation/__tests__/LoneAnonymousOperationRule-test.js rename to src/validation/__tests__/LoneAnonymousOperationRule-test.ts diff --git a/src/validation/__tests__/LoneSchemaDefinitionRule-test.js b/src/validation/__tests__/LoneSchemaDefinitionRule-test.ts similarity index 98% rename from src/validation/__tests__/LoneSchemaDefinitionRule-test.js rename to src/validation/__tests__/LoneSchemaDefinitionRule-test.ts index 6e040576b29..caedbca92b7 100644 --- a/src/validation/__tests__/LoneSchemaDefinitionRule-test.js +++ b/src/validation/__tests__/LoneSchemaDefinitionRule-test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'mocha'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; diff --git a/src/validation/__tests__/NoDeprecatedCustomRule-test.js b/src/validation/__tests__/NoDeprecatedCustomRule-test.ts similarity index 100% rename from src/validation/__tests__/NoDeprecatedCustomRule-test.js rename to src/validation/__tests__/NoDeprecatedCustomRule-test.ts diff --git a/src/validation/__tests__/NoFragmentCyclesRule-test.js b/src/validation/__tests__/NoFragmentCyclesRule-test.ts similarity index 100% rename from src/validation/__tests__/NoFragmentCyclesRule-test.js rename to src/validation/__tests__/NoFragmentCyclesRule-test.ts diff --git a/src/validation/__tests__/NoSchemaIntrospectionCustomRule-test.js b/src/validation/__tests__/NoSchemaIntrospectionCustomRule-test.ts similarity index 100% rename from src/validation/__tests__/NoSchemaIntrospectionCustomRule-test.js rename to src/validation/__tests__/NoSchemaIntrospectionCustomRule-test.ts diff --git a/src/validation/__tests__/NoUndefinedVariablesRule-test.js b/src/validation/__tests__/NoUndefinedVariablesRule-test.ts similarity index 100% rename from src/validation/__tests__/NoUndefinedVariablesRule-test.js rename to src/validation/__tests__/NoUndefinedVariablesRule-test.ts diff --git a/src/validation/__tests__/NoUnusedFragmentsRule-test.js b/src/validation/__tests__/NoUnusedFragmentsRule-test.ts similarity index 100% rename from src/validation/__tests__/NoUnusedFragmentsRule-test.js rename to src/validation/__tests__/NoUnusedFragmentsRule-test.ts diff --git a/src/validation/__tests__/NoUnusedVariablesRule-test.js b/src/validation/__tests__/NoUnusedVariablesRule-test.ts similarity index 100% rename from src/validation/__tests__/NoUnusedVariablesRule-test.js rename to src/validation/__tests__/NoUnusedVariablesRule-test.ts diff --git a/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.js b/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.ts similarity index 99% rename from src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.js rename to src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.ts index 080f859b89d..309e098c510 100644 --- a/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.js +++ b/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'mocha'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; diff --git a/src/validation/__tests__/PossibleFragmentSpreadsRule-test.js b/src/validation/__tests__/PossibleFragmentSpreadsRule-test.ts similarity index 100% rename from src/validation/__tests__/PossibleFragmentSpreadsRule-test.js rename to src/validation/__tests__/PossibleFragmentSpreadsRule-test.ts diff --git a/src/validation/__tests__/PossibleTypeExtensionsRule-test.js b/src/validation/__tests__/PossibleTypeExtensionsRule-test.ts similarity index 99% rename from src/validation/__tests__/PossibleTypeExtensionsRule-test.js rename to src/validation/__tests__/PossibleTypeExtensionsRule-test.ts index 932f7ccef62..4f1e488c768 100644 --- a/src/validation/__tests__/PossibleTypeExtensionsRule-test.js +++ b/src/validation/__tests__/PossibleTypeExtensionsRule-test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'mocha'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; diff --git a/src/validation/__tests__/ProvidedRequiredArgumentsRule-test.js b/src/validation/__tests__/ProvidedRequiredArgumentsRule-test.ts similarity index 99% rename from src/validation/__tests__/ProvidedRequiredArgumentsRule-test.js rename to src/validation/__tests__/ProvidedRequiredArgumentsRule-test.ts index 7976f46bd21..5803027ddc1 100644 --- a/src/validation/__tests__/ProvidedRequiredArgumentsRule-test.js +++ b/src/validation/__tests__/ProvidedRequiredArgumentsRule-test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'mocha'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; diff --git a/src/validation/__tests__/ScalarLeafsRule-test.js b/src/validation/__tests__/ScalarLeafsRule-test.ts similarity index 100% rename from src/validation/__tests__/ScalarLeafsRule-test.js rename to src/validation/__tests__/ScalarLeafsRule-test.ts diff --git a/src/validation/__tests__/SingleFieldSubscriptionsRule-test.js b/src/validation/__tests__/SingleFieldSubscriptionsRule-test.ts similarity index 100% rename from src/validation/__tests__/SingleFieldSubscriptionsRule-test.js rename to src/validation/__tests__/SingleFieldSubscriptionsRule-test.ts diff --git a/src/validation/__tests__/UniqueArgumentNamesRule-test.js b/src/validation/__tests__/UniqueArgumentNamesRule-test.ts similarity index 100% rename from src/validation/__tests__/UniqueArgumentNamesRule-test.js rename to src/validation/__tests__/UniqueArgumentNamesRule-test.ts diff --git a/src/validation/__tests__/UniqueDirectiveNamesRule-test.js b/src/validation/__tests__/UniqueDirectiveNamesRule-test.ts similarity index 97% rename from src/validation/__tests__/UniqueDirectiveNamesRule-test.js rename to src/validation/__tests__/UniqueDirectiveNamesRule-test.ts index 5e898998ed2..d8737a8498a 100644 --- a/src/validation/__tests__/UniqueDirectiveNamesRule-test.js +++ b/src/validation/__tests__/UniqueDirectiveNamesRule-test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'mocha'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; diff --git a/src/validation/__tests__/UniqueDirectivesPerLocationRule-test.js b/src/validation/__tests__/UniqueDirectivesPerLocationRule-test.ts similarity index 99% rename from src/validation/__tests__/UniqueDirectivesPerLocationRule-test.js rename to src/validation/__tests__/UniqueDirectivesPerLocationRule-test.ts index 79a7522419b..87d45da44e9 100644 --- a/src/validation/__tests__/UniqueDirectivesPerLocationRule-test.js +++ b/src/validation/__tests__/UniqueDirectivesPerLocationRule-test.ts @@ -2,7 +2,7 @@ import { describe, it } from 'mocha'; import { parse } from '../../language/parser'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { extendSchema } from '../../utilities/extendSchema'; diff --git a/src/validation/__tests__/UniqueEnumValueNamesRule-test.js b/src/validation/__tests__/UniqueEnumValueNamesRule-test.ts similarity index 98% rename from src/validation/__tests__/UniqueEnumValueNamesRule-test.js rename to src/validation/__tests__/UniqueEnumValueNamesRule-test.ts index a97ac3b6878..e4d08a4649e 100644 --- a/src/validation/__tests__/UniqueEnumValueNamesRule-test.js +++ b/src/validation/__tests__/UniqueEnumValueNamesRule-test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'mocha'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; diff --git a/src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.js b/src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.ts similarity index 99% rename from src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.js rename to src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.ts index c27182d1acb..e678b6a57f5 100644 --- a/src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.js +++ b/src/validation/__tests__/UniqueFieldDefinitionNamesRule-test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'mocha'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; diff --git a/src/validation/__tests__/UniqueFragmentNamesRule-test.js b/src/validation/__tests__/UniqueFragmentNamesRule-test.ts similarity index 100% rename from src/validation/__tests__/UniqueFragmentNamesRule-test.js rename to src/validation/__tests__/UniqueFragmentNamesRule-test.ts diff --git a/src/validation/__tests__/UniqueInputFieldNamesRule-test.js b/src/validation/__tests__/UniqueInputFieldNamesRule-test.ts similarity index 100% rename from src/validation/__tests__/UniqueInputFieldNamesRule-test.js rename to src/validation/__tests__/UniqueInputFieldNamesRule-test.ts diff --git a/src/validation/__tests__/UniqueOperationNamesRule-test.js b/src/validation/__tests__/UniqueOperationNamesRule-test.ts similarity index 100% rename from src/validation/__tests__/UniqueOperationNamesRule-test.js rename to src/validation/__tests__/UniqueOperationNamesRule-test.ts diff --git a/src/validation/__tests__/UniqueOperationTypesRule-test.js b/src/validation/__tests__/UniqueOperationTypesRule-test.ts similarity index 99% rename from src/validation/__tests__/UniqueOperationTypesRule-test.js rename to src/validation/__tests__/UniqueOperationTypesRule-test.ts index fd73040c448..e5fecfe3fbe 100644 --- a/src/validation/__tests__/UniqueOperationTypesRule-test.js +++ b/src/validation/__tests__/UniqueOperationTypesRule-test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'mocha'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; diff --git a/src/validation/__tests__/UniqueTypeNamesRule-test.js b/src/validation/__tests__/UniqueTypeNamesRule-test.ts similarity index 98% rename from src/validation/__tests__/UniqueTypeNamesRule-test.js rename to src/validation/__tests__/UniqueTypeNamesRule-test.ts index 6525275e924..884decbdc94 100644 --- a/src/validation/__tests__/UniqueTypeNamesRule-test.js +++ b/src/validation/__tests__/UniqueTypeNamesRule-test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'mocha'; -import type { GraphQLSchema } from '../../type/schema'; +import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; diff --git a/src/validation/__tests__/UniqueVariableNamesRule-test.js b/src/validation/__tests__/UniqueVariableNamesRule-test.ts similarity index 100% rename from src/validation/__tests__/UniqueVariableNamesRule-test.js rename to src/validation/__tests__/UniqueVariableNamesRule-test.ts diff --git a/src/validation/__tests__/ValuesOfCorrectTypeRule-test.js b/src/validation/__tests__/ValuesOfCorrectTypeRule-test.ts similarity index 100% rename from src/validation/__tests__/ValuesOfCorrectTypeRule-test.js rename to src/validation/__tests__/ValuesOfCorrectTypeRule-test.ts diff --git a/src/validation/__tests__/VariablesAreInputTypesRule-test.js b/src/validation/__tests__/VariablesAreInputTypesRule-test.ts similarity index 100% rename from src/validation/__tests__/VariablesAreInputTypesRule-test.js rename to src/validation/__tests__/VariablesAreInputTypesRule-test.ts diff --git a/src/validation/__tests__/VariablesInAllowedPositionRule-test.js b/src/validation/__tests__/VariablesInAllowedPositionRule-test.ts similarity index 100% rename from src/validation/__tests__/VariablesInAllowedPositionRule-test.js rename to src/validation/__tests__/VariablesInAllowedPositionRule-test.ts diff --git a/src/validation/__tests__/harness.js b/src/validation/__tests__/harness.ts similarity index 97% rename from src/validation/__tests__/harness.js rename to src/validation/__tests__/harness.ts index 99683412d83..021d73be354 100644 --- a/src/validation/__tests__/harness.js +++ b/src/validation/__tests__/harness.ts @@ -7,7 +7,7 @@ import { GraphQLSchema } from '../../type/schema'; import { buildSchema } from '../../utilities/buildASTSchema'; import { validate, validateSDL } from '../validate'; -import type { ValidationRule, SDLValidationRule } from '../ValidationContext'; +import { ValidationRule, SDLValidationRule } from '../ValidationContext'; export const testSchema = buildSchema(` interface Being { @@ -160,7 +160,7 @@ export function expectValidationErrors( } export function expectSDLValidationErrors( - schema: ?GraphQLSchema, + schema: GraphQLSchema | null | undefined, rule: SDLValidationRule, sdlStr: string, ): any { diff --git a/src/validation/__tests__/validation-test.js b/src/validation/__tests__/validation-test.ts similarity index 97% rename from src/validation/__tests__/validation-test.js rename to src/validation/__tests__/validation-test.ts index b1113d2d012..dfe2be28a0e 100644 --- a/src/validation/__tests__/validation-test.js +++ b/src/validation/__tests__/validation-test.ts @@ -8,7 +8,7 @@ import { parse } from '../../language/parser'; import { TypeInfo } from '../../utilities/TypeInfo'; import { buildSchema } from '../../utilities/buildASTSchema'; -import type { ValidationContext } from '../ValidationContext'; +import { ValidationContext } from '../ValidationContext'; import { validate } from '../validate'; import { testSchema } from './harness'; @@ -129,7 +129,7 @@ describe('Validate: Limit maximum number of validation errors', () => { `; const doc = parse(query, { noLocation: true }); - function validateDocument(options: {| maxErrors?: number |}) { + function validateDocument(options: { maxErrors?: number }) { return validate(testSchema, doc, undefined, undefined, options); } diff --git a/src/validation/index.js b/src/validation/index.ts similarity index 98% rename from src/validation/index.js rename to src/validation/index.ts index c0f24a0316f..a5c806a574c 100644 --- a/src/validation/index.js +++ b/src/validation/index.ts @@ -1,7 +1,7 @@ export { validate } from './validate'; export { ValidationContext } from './ValidationContext'; -export type { ValidationRule } from './ValidationContext'; +export { ValidationRule } from './ValidationContext'; // All validation rules in the GraphQL Specification. export { specifiedRules } from './specifiedRules'; diff --git a/src/validation/rules/ExecutableDefinitionsRule.js b/src/validation/rules/ExecutableDefinitionsRule.ts similarity index 89% rename from src/validation/rules/ExecutableDefinitionsRule.js rename to src/validation/rules/ExecutableDefinitionsRule.ts index c446e000e18..d1f3a810528 100644 --- a/src/validation/rules/ExecutableDefinitionsRule.js +++ b/src/validation/rules/ExecutableDefinitionsRule.ts @@ -1,10 +1,10 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; import { Kind } from '../../language/kinds'; import { isExecutableDefinitionNode } from '../../language/predicates'; -import type { ASTValidationContext } from '../ValidationContext'; +import { ASTValidationContext } from '../ValidationContext'; /** * Executable definitions diff --git a/src/validation/rules/FieldsOnCorrectTypeRule.js b/src/validation/rules/FieldsOnCorrectTypeRule.ts similarity index 93% rename from src/validation/rules/FieldsOnCorrectTypeRule.js rename to src/validation/rules/FieldsOnCorrectTypeRule.ts index 734667028a2..eb60453c8e1 100644 --- a/src/validation/rules/FieldsOnCorrectTypeRule.js +++ b/src/validation/rules/FieldsOnCorrectTypeRule.ts @@ -3,11 +3,11 @@ import suggestionList from '../../jsutils/suggestionList'; import { GraphQLError } from '../../error/GraphQLError'; -import type { FieldNode } from '../../language/ast'; -import type { ASTVisitor } from '../../language/visitor'; +import { FieldNode } from '../../language/ast'; +import { ASTVisitor } from '../../language/visitor'; -import type { GraphQLSchema } from '../../type/schema'; -import type { +import { GraphQLSchema } from '../../type/schema'; +import { GraphQLOutputType, GraphQLObjectType, GraphQLInterfaceType, @@ -18,7 +18,7 @@ import { isAbstractType, } from '../../type/definition'; -import type { ValidationContext } from '../ValidationContext'; +import { ValidationContext } from '../ValidationContext'; /** * Fields on correct type @@ -80,7 +80,7 @@ function getSuggestedTypeNames( } const suggestedTypes: Set< - GraphQLObjectType | GraphQLInterfaceType, + GraphQLObjectType | GraphQLInterfaceType > = new Set(); const usageCount = Object.create(null); for (const possibleType of schema.getPossibleTypes(type)) { diff --git a/src/validation/rules/FragmentsOnCompositeTypesRule.js b/src/validation/rules/FragmentsOnCompositeTypesRule.ts similarity index 92% rename from src/validation/rules/FragmentsOnCompositeTypesRule.js rename to src/validation/rules/FragmentsOnCompositeTypesRule.ts index 75f49158c7e..1fa4b1595d5 100644 --- a/src/validation/rules/FragmentsOnCompositeTypesRule.js +++ b/src/validation/rules/FragmentsOnCompositeTypesRule.ts @@ -1,13 +1,13 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; import { print } from '../../language/printer'; import { isCompositeType } from '../../type/definition'; import { typeFromAST } from '../../utilities/typeFromAST'; -import type { ValidationContext } from '../ValidationContext'; +import { ValidationContext } from '../ValidationContext'; /** * Fragments on composite type diff --git a/src/validation/rules/KnownArgumentNamesRule.js b/src/validation/rules/KnownArgumentNamesRule.ts similarity index 94% rename from src/validation/rules/KnownArgumentNamesRule.js rename to src/validation/rules/KnownArgumentNamesRule.ts index b1fd082463b..de9c3641e51 100644 --- a/src/validation/rules/KnownArgumentNamesRule.js +++ b/src/validation/rules/KnownArgumentNamesRule.ts @@ -3,15 +3,12 @@ import suggestionList from '../../jsutils/suggestionList'; import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; import { Kind } from '../../language/kinds'; import { specifiedDirectives } from '../../type/directives'; -import type { - ValidationContext, - SDLValidationContext, -} from '../ValidationContext'; +import { ValidationContext, SDLValidationContext } from '../ValidationContext'; /** * Known argument names diff --git a/src/validation/rules/KnownDirectivesRule.js b/src/validation/rules/KnownDirectivesRule.ts similarity index 90% rename from src/validation/rules/KnownDirectivesRule.js rename to src/validation/rules/KnownDirectivesRule.ts index 8c2e60de887..ce7babe5e6b 100644 --- a/src/validation/rules/KnownDirectivesRule.js +++ b/src/validation/rules/KnownDirectivesRule.ts @@ -3,18 +3,15 @@ import invariant from '../../jsutils/invariant'; import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; -import type { ASTNode, OperationTypeNode } from '../../language/ast'; -import type { DirectiveLocationEnum } from '../../language/directiveLocation'; +import { ASTVisitor } from '../../language/visitor'; +import { ASTNode, OperationTypeNode } from '../../language/ast'; +import { DirectiveLocationEnum } from '../../language/directiveLocation'; import { Kind } from '../../language/kinds'; import { DirectiveLocation } from '../../language/directiveLocation'; import { specifiedDirectives } from '../../type/directives'; -import type { - ValidationContext, - SDLValidationContext, -} from '../ValidationContext'; +import { ValidationContext, SDLValidationContext } from '../ValidationContext'; /** * Known directives @@ -68,7 +65,7 @@ export function KnownDirectivesRule( } function getDirectiveLocationForASTPath( - ancestors: $ReadOnlyArray>, + ancestors: ReadonlyArray>, ): DirectiveLocationEnum | void { const appliedTo = ancestors[ancestors.length - 1]; invariant(!Array.isArray(appliedTo)); @@ -133,5 +130,5 @@ function getDirectiveLocationForOperation( } // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false, 'Unexpected operation: ' + inspect((operation: empty))); + invariant(false, 'Unexpected operation: ' + inspect(operation as never)); } diff --git a/src/validation/rules/KnownFragmentNamesRule.js b/src/validation/rules/KnownFragmentNamesRule.ts similarity index 83% rename from src/validation/rules/KnownFragmentNamesRule.js rename to src/validation/rules/KnownFragmentNamesRule.ts index 0f3412bb456..f0595234799 100644 --- a/src/validation/rules/KnownFragmentNamesRule.js +++ b/src/validation/rules/KnownFragmentNamesRule.ts @@ -1,8 +1,8 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; -import type { ValidationContext } from '../ValidationContext'; +import { ValidationContext } from '../ValidationContext'; /** * Known fragment names diff --git a/src/validation/rules/KnownTypeNamesRule.js b/src/validation/rules/KnownTypeNamesRule.ts similarity index 88% rename from src/validation/rules/KnownTypeNamesRule.js rename to src/validation/rules/KnownTypeNamesRule.ts index 38efd5a603d..214bbccf69b 100644 --- a/src/validation/rules/KnownTypeNamesRule.js +++ b/src/validation/rules/KnownTypeNamesRule.ts @@ -3,8 +3,8 @@ import suggestionList from '../../jsutils/suggestionList'; import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTNode } from '../../language/ast'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTNode } from '../../language/ast'; +import { ASTVisitor } from '../../language/visitor'; import { isTypeDefinitionNode, isTypeSystemDefinitionNode, @@ -14,10 +14,7 @@ import { import { specifiedScalarTypes } from '../../type/scalars'; import { introspectionTypes } from '../../type/introspection'; -import type { - ValidationContext, - SDLValidationContext, -} from '../ValidationContext'; +import { ValidationContext, SDLValidationContext } from '../ValidationContext'; /** * Known type names @@ -75,7 +72,7 @@ function isStandardTypeName(typeName: string): boolean { return standardTypeNames.indexOf(typeName) !== -1; } -function isSDLNode(value: ASTNode | $ReadOnlyArray): boolean { +function isSDLNode(value: ASTNode | ReadonlyArray): boolean { return ( !Array.isArray(value) && (isTypeSystemDefinitionNode(value) || isTypeSystemExtensionNode(value)) diff --git a/src/validation/rules/LoneAnonymousOperationRule.js b/src/validation/rules/LoneAnonymousOperationRule.ts similarity index 87% rename from src/validation/rules/LoneAnonymousOperationRule.js rename to src/validation/rules/LoneAnonymousOperationRule.ts index 617c80639f2..0178bc48eb2 100644 --- a/src/validation/rules/LoneAnonymousOperationRule.js +++ b/src/validation/rules/LoneAnonymousOperationRule.ts @@ -1,9 +1,9 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; import { Kind } from '../../language/kinds'; -import type { ASTValidationContext } from '../ValidationContext'; +import { ASTValidationContext } from '../ValidationContext'; /** * Lone anonymous operation diff --git a/src/validation/rules/LoneSchemaDefinitionRule.js b/src/validation/rules/LoneSchemaDefinitionRule.ts similarity index 88% rename from src/validation/rules/LoneSchemaDefinitionRule.js rename to src/validation/rules/LoneSchemaDefinitionRule.ts index 1c2b02371e7..9652caf6a66 100644 --- a/src/validation/rules/LoneSchemaDefinitionRule.js +++ b/src/validation/rules/LoneSchemaDefinitionRule.ts @@ -1,7 +1,7 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; -import type { SDLValidationContext } from '../ValidationContext'; +import { SDLValidationContext } from '../ValidationContext'; /** * Lone Schema definition diff --git a/src/validation/rules/NoFragmentCyclesRule.js b/src/validation/rules/NoFragmentCyclesRule.ts similarity index 91% rename from src/validation/rules/NoFragmentCyclesRule.js rename to src/validation/rules/NoFragmentCyclesRule.ts index 54fba26e438..628a5406677 100644 --- a/src/validation/rules/NoFragmentCyclesRule.js +++ b/src/validation/rules/NoFragmentCyclesRule.ts @@ -1,9 +1,9 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; -import type { FragmentDefinitionNode } from '../../language/ast'; +import { ASTVisitor } from '../../language/visitor'; +import { FragmentDefinitionNode } from '../../language/ast'; -import type { ASTValidationContext } from '../ValidationContext'; +import { ASTValidationContext } from '../ValidationContext'; export function NoFragmentCyclesRule( context: ASTValidationContext, diff --git a/src/validation/rules/NoUndefinedVariablesRule.js b/src/validation/rules/NoUndefinedVariablesRule.ts similarity index 90% rename from src/validation/rules/NoUndefinedVariablesRule.js rename to src/validation/rules/NoUndefinedVariablesRule.ts index de1a84807fa..10c4d765e70 100644 --- a/src/validation/rules/NoUndefinedVariablesRule.js +++ b/src/validation/rules/NoUndefinedVariablesRule.ts @@ -1,8 +1,8 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; -import type { ValidationContext } from '../ValidationContext'; +import { ValidationContext } from '../ValidationContext'; /** * No undefined variables diff --git a/src/validation/rules/NoUnusedFragmentsRule.js b/src/validation/rules/NoUnusedFragmentsRule.ts similarity index 91% rename from src/validation/rules/NoUnusedFragmentsRule.js rename to src/validation/rules/NoUnusedFragmentsRule.ts index d69bf241cfa..f3854e02a2d 100644 --- a/src/validation/rules/NoUnusedFragmentsRule.js +++ b/src/validation/rules/NoUnusedFragmentsRule.ts @@ -1,8 +1,8 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; -import type { ASTValidationContext } from '../ValidationContext'; +import { ASTValidationContext } from '../ValidationContext'; /** * No unused fragments diff --git a/src/validation/rules/NoUnusedVariablesRule.js b/src/validation/rules/NoUnusedVariablesRule.ts similarity index 91% rename from src/validation/rules/NoUnusedVariablesRule.js rename to src/validation/rules/NoUnusedVariablesRule.ts index 70bc81c9419..dc368d72bc2 100644 --- a/src/validation/rules/NoUnusedVariablesRule.js +++ b/src/validation/rules/NoUnusedVariablesRule.ts @@ -1,8 +1,8 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; -import type { ValidationContext } from '../ValidationContext'; +import { ValidationContext } from '../ValidationContext'; /** * No unused variables diff --git a/src/validation/rules/OverlappingFieldsCanBeMergedRule.js b/src/validation/rules/OverlappingFieldsCanBeMergedRule.ts similarity index 97% rename from src/validation/rules/OverlappingFieldsCanBeMergedRule.js rename to src/validation/rules/OverlappingFieldsCanBeMergedRule.ts index 983f69099d7..e74b2b7bd92 100644 --- a/src/validation/rules/OverlappingFieldsCanBeMergedRule.js +++ b/src/validation/rules/OverlappingFieldsCanBeMergedRule.ts @@ -1,12 +1,12 @@ import objectEntries from '../../polyfills/objectEntries'; -import type { ObjMap } from '../../jsutils/ObjMap'; +import { ObjMap } from '../../jsutils/ObjMap'; import inspect from '../../jsutils/inspect'; import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; -import type { +import { ASTVisitor } from '../../language/visitor'; +import { SelectionSetNode, ValueNode, FieldNode, @@ -16,7 +16,7 @@ import type { import { Kind } from '../../language/kinds'; import { print } from '../../language/printer'; -import type { +import { GraphQLNamedType, GraphQLOutputType, GraphQLCompositeType, @@ -33,7 +33,7 @@ import { import { typeFromAST } from '../../utilities/typeFromAST'; -import type { ValidationContext } from '../ValidationContext'; +import { ValidationContext } from '../ValidationContext'; function reasonMessage(reason: ConflictReasonMessage): string { if (Array.isArray(reason)) { @@ -99,7 +99,7 @@ type ConflictReasonMessage = string | Array; type NodeAndDef = [ GraphQLCompositeType, FieldNode, - ?GraphQLField, + GraphQLField | null | undefined, ]; // Map of array of those. type NodeAndDefCollection = ObjMap>; @@ -158,7 +158,6 @@ type NodeAndDefCollection = ObjMap>; * comparison is made "between" the two fragments. * */ - // Find all conflicts found "within" a selection set, including those found // via spreading in fragments. Called when visiting each SelectionSet in the // GraphQL Document. @@ -166,7 +165,7 @@ function findConflictsWithinSelectionSet( context: ValidationContext, cachedFieldsAndFragmentNames, comparedFragmentPairs: PairSet, - parentType: ?GraphQLNamedType, + parentType: GraphQLNamedType | null | undefined, selectionSet: SelectionSetNode, ): Array { const conflicts = []; @@ -369,9 +368,9 @@ function findConflictsBetweenSubSelectionSets( cachedFieldsAndFragmentNames, comparedFragmentPairs: PairSet, areMutuallyExclusive: boolean, - parentType1: ?GraphQLNamedType, + parentType1: GraphQLNamedType | null | undefined, selectionSet1: SelectionSetNode, - parentType2: ?GraphQLNamedType, + parentType2: GraphQLNamedType | null | undefined, selectionSet2: SelectionSetNode, ): Array { const conflicts = []; @@ -541,7 +540,7 @@ function findConflict( responseName: string, field1: NodeAndDef, field2: NodeAndDef, -): ?Conflict { +): Conflict | null | undefined { const [parentType1, node1, def1] = field1; const [parentType2, node2, def2] = field2; @@ -623,8 +622,8 @@ function findConflict( } function sameArguments( - arguments1: $ReadOnlyArray, - arguments2: $ReadOnlyArray, + arguments1: ReadonlyArray, + arguments2: ReadonlyArray, ): boolean { if (arguments1.length !== arguments2.length) { return false; @@ -679,7 +678,7 @@ function doTypesConflict( function getFieldsAndFragmentNames( context: ValidationContext, cachedFieldsAndFragmentNames, - parentType: ?GraphQLNamedType, + parentType: GraphQLNamedType | null | undefined, selectionSet: SelectionSetNode, ): [NodeAndDefCollection, Array] { let cached = cachedFieldsAndFragmentNames.get(selectionSet); @@ -723,7 +722,7 @@ function getReferencedFieldsAndFragmentNames( function _collectFieldsAndFragmentNames( context: ValidationContext, - parentType: ?GraphQLNamedType, + parentType: GraphQLNamedType | null | undefined, selectionSet: SelectionSetNode, nodeAndDefs, fragmentNames, @@ -769,11 +768,11 @@ function _collectFieldsAndFragmentNames( // Given a series of Conflicts which occurred between two sub-fields, generate // a single Conflict. function subfieldConflicts( - conflicts: $ReadOnlyArray, + conflicts: ReadonlyArray, responseName: string, node1: FieldNode, node2: FieldNode, -): ?Conflict { +): Conflict | null | undefined { if (conflicts.length > 0) { return [ [responseName, conflicts.map(([reason]) => reason)], diff --git a/src/validation/rules/PossibleFragmentSpreadsRule.js b/src/validation/rules/PossibleFragmentSpreadsRule.ts similarity index 90% rename from src/validation/rules/PossibleFragmentSpreadsRule.js rename to src/validation/rules/PossibleFragmentSpreadsRule.ts index ba4e9ca5ef3..8995a43180d 100644 --- a/src/validation/rules/PossibleFragmentSpreadsRule.js +++ b/src/validation/rules/PossibleFragmentSpreadsRule.ts @@ -2,15 +2,15 @@ import inspect from '../../jsutils/inspect'; import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; -import type { GraphQLCompositeType } from '../../type/definition'; +import { GraphQLCompositeType } from '../../type/definition'; import { isCompositeType } from '../../type/definition'; import { typeFromAST } from '../../utilities/typeFromAST'; import { doTypesOverlap } from '../../utilities/typeComparators'; -import type { ValidationContext } from '../ValidationContext'; +import { ValidationContext } from '../ValidationContext'; /** * Possible fragment spread @@ -66,7 +66,7 @@ export function PossibleFragmentSpreadsRule( function getFragmentType( context: ValidationContext, name: string, -): ?GraphQLCompositeType { +): GraphQLCompositeType | null | undefined { const frag = context.getFragment(name); if (frag) { const type = typeFromAST(context.getSchema(), frag.typeCondition); diff --git a/src/validation/rules/PossibleTypeExtensionsRule.js b/src/validation/rules/PossibleTypeExtensionsRule.ts similarity index 91% rename from src/validation/rules/PossibleTypeExtensionsRule.js rename to src/validation/rules/PossibleTypeExtensionsRule.ts index 2f098191eff..eb1dfc663c8 100644 --- a/src/validation/rules/PossibleTypeExtensionsRule.js +++ b/src/validation/rules/PossibleTypeExtensionsRule.ts @@ -5,13 +5,13 @@ import suggestionList from '../../jsutils/suggestionList'; import { GraphQLError } from '../../error/GraphQLError'; -import type { KindEnum } from '../../language/kinds'; -import type { ASTVisitor } from '../../language/visitor'; -import type { TypeExtensionNode } from '../../language/ast'; +import { KindEnum } from '../../language/kinds'; +import { ASTVisitor } from '../../language/visitor'; +import { TypeExtensionNode } from '../../language/ast'; import { Kind } from '../../language/kinds'; import { isTypeDefinitionNode } from '../../language/predicates'; -import type { GraphQLNamedType } from '../../type/definition'; +import { GraphQLNamedType } from '../../type/definition'; import { isScalarType, isObjectType, @@ -21,7 +21,7 @@ import { isInputObjectType, } from '../../type/definition'; -import type { SDLValidationContext } from '../ValidationContext'; +import { SDLValidationContext } from '../ValidationContext'; /** * Possible type extension @@ -120,7 +120,7 @@ function typeToExtKind(type: GraphQLNamedType): KindEnum { } // istanbul ignore next (Not reachable. All possible types have been considered) - invariant(false, 'Unexpected type: ' + inspect((type: empty))); + invariant(false, 'Unexpected type: ' + inspect(type as never)); } function extensionKindToTypeName(kind: KindEnum): string { diff --git a/src/validation/rules/ProvidedRequiredArgumentsRule.js b/src/validation/rules/ProvidedRequiredArgumentsRule.ts similarity index 94% rename from src/validation/rules/ProvidedRequiredArgumentsRule.js rename to src/validation/rules/ProvidedRequiredArgumentsRule.ts index b9ff7a032b3..f516f1015d8 100644 --- a/src/validation/rules/ProvidedRequiredArgumentsRule.js +++ b/src/validation/rules/ProvidedRequiredArgumentsRule.ts @@ -3,18 +3,15 @@ import keyMap from '../../jsutils/keyMap'; import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; -import type { InputValueDefinitionNode } from '../../language/ast'; +import { ASTVisitor } from '../../language/visitor'; +import { InputValueDefinitionNode } from '../../language/ast'; import { Kind } from '../../language/kinds'; import { print } from '../../language/printer'; import { specifiedDirectives } from '../../type/directives'; import { isType, isRequiredArgument } from '../../type/definition'; -import type { - ValidationContext, - SDLValidationContext, -} from '../ValidationContext'; +import { ValidationContext, SDLValidationContext } from '../ValidationContext'; /** * Provided required arguments diff --git a/src/validation/rules/ScalarLeafsRule.js b/src/validation/rules/ScalarLeafsRule.ts similarity index 88% rename from src/validation/rules/ScalarLeafsRule.js rename to src/validation/rules/ScalarLeafsRule.ts index a0c0c6cc408..7dfec238398 100644 --- a/src/validation/rules/ScalarLeafsRule.js +++ b/src/validation/rules/ScalarLeafsRule.ts @@ -2,12 +2,12 @@ import inspect from '../../jsutils/inspect'; import { GraphQLError } from '../../error/GraphQLError'; -import type { FieldNode } from '../../language/ast'; -import type { ASTVisitor } from '../../language/visitor'; +import { FieldNode } from '../../language/ast'; +import { ASTVisitor } from '../../language/visitor'; import { getNamedType, isLeafType } from '../../type/definition'; -import type { ValidationContext } from '../ValidationContext'; +import { ValidationContext } from '../ValidationContext'; /** * Scalar leafs diff --git a/src/validation/rules/SingleFieldSubscriptionsRule.js b/src/validation/rules/SingleFieldSubscriptionsRule.ts similarity index 81% rename from src/validation/rules/SingleFieldSubscriptionsRule.js rename to src/validation/rules/SingleFieldSubscriptionsRule.ts index 760fe3c144d..b427c76ee50 100644 --- a/src/validation/rules/SingleFieldSubscriptionsRule.js +++ b/src/validation/rules/SingleFieldSubscriptionsRule.ts @@ -1,9 +1,9 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; -import type { OperationDefinitionNode } from '../../language/ast'; +import { ASTVisitor } from '../../language/visitor'; +import { OperationDefinitionNode } from '../../language/ast'; -import type { ASTValidationContext } from '../ValidationContext'; +import { ASTValidationContext } from '../ValidationContext'; /** * Subscriptions must only include one field. diff --git a/src/validation/rules/UniqueArgumentNamesRule.js b/src/validation/rules/UniqueArgumentNamesRule.ts similarity index 87% rename from src/validation/rules/UniqueArgumentNamesRule.js rename to src/validation/rules/UniqueArgumentNamesRule.ts index 73289efd2f3..b88b04b8d1e 100644 --- a/src/validation/rules/UniqueArgumentNamesRule.js +++ b/src/validation/rules/UniqueArgumentNamesRule.ts @@ -1,7 +1,7 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; -import type { ASTValidationContext } from '../ValidationContext'; +import { ASTValidationContext } from '../ValidationContext'; /** * Unique argument names diff --git a/src/validation/rules/UniqueDirectiveNamesRule.js b/src/validation/rules/UniqueDirectiveNamesRule.ts similarity index 89% rename from src/validation/rules/UniqueDirectiveNamesRule.js rename to src/validation/rules/UniqueDirectiveNamesRule.ts index 0d87d9deb41..da638630f97 100644 --- a/src/validation/rules/UniqueDirectiveNamesRule.js +++ b/src/validation/rules/UniqueDirectiveNamesRule.ts @@ -1,7 +1,7 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; -import type { SDLValidationContext } from '../ValidationContext'; +import { SDLValidationContext } from '../ValidationContext'; /** * Unique directive names diff --git a/src/validation/rules/UniqueDirectivesPerLocationRule.js b/src/validation/rules/UniqueDirectivesPerLocationRule.ts similarity index 94% rename from src/validation/rules/UniqueDirectivesPerLocationRule.js rename to src/validation/rules/UniqueDirectivesPerLocationRule.ts index a21c0817903..8f070468cb1 100644 --- a/src/validation/rules/UniqueDirectivesPerLocationRule.js +++ b/src/validation/rules/UniqueDirectivesPerLocationRule.ts @@ -1,7 +1,7 @@ import { GraphQLError } from '../../error/GraphQLError'; import { Kind } from '../../language/kinds'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; import { isTypeDefinitionNode, isTypeExtensionNode, @@ -9,10 +9,7 @@ import { import { specifiedDirectives } from '../../type/directives'; -import type { - SDLValidationContext, - ValidationContext, -} from '../ValidationContext'; +import { SDLValidationContext, ValidationContext } from '../ValidationContext'; /** * Unique directive names per location diff --git a/src/validation/rules/UniqueEnumValueNamesRule.js b/src/validation/rules/UniqueEnumValueNamesRule.ts similarity index 93% rename from src/validation/rules/UniqueEnumValueNamesRule.js rename to src/validation/rules/UniqueEnumValueNamesRule.ts index 28ba1142484..20a8547cb5e 100644 --- a/src/validation/rules/UniqueEnumValueNamesRule.js +++ b/src/validation/rules/UniqueEnumValueNamesRule.ts @@ -1,14 +1,14 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; -import type { +import { ASTVisitor } from '../../language/visitor'; +import { EnumTypeDefinitionNode, EnumTypeExtensionNode, } from '../../language/ast'; import { isEnumType } from '../../type/definition'; -import type { SDLValidationContext } from '../ValidationContext'; +import { SDLValidationContext } from '../ValidationContext'; /** * Unique enum value names diff --git a/src/validation/rules/UniqueFieldDefinitionNamesRule.js b/src/validation/rules/UniqueFieldDefinitionNamesRule.ts similarity index 88% rename from src/validation/rules/UniqueFieldDefinitionNamesRule.js rename to src/validation/rules/UniqueFieldDefinitionNamesRule.ts index f912a8489fb..8f40365460b 100644 --- a/src/validation/rules/UniqueFieldDefinitionNamesRule.js +++ b/src/validation/rules/UniqueFieldDefinitionNamesRule.ts @@ -1,20 +1,20 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; -import type { +import { ASTVisitor } from '../../language/visitor'; +import { NameNode, FieldDefinitionNode, InputValueDefinitionNode, } from '../../language/ast'; -import type { GraphQLNamedType } from '../../type/definition'; +import { GraphQLNamedType } from '../../type/definition'; import { isObjectType, isInterfaceType, isInputObjectType, } from '../../type/definition'; -import type { SDLValidationContext } from '../ValidationContext'; +import { SDLValidationContext } from '../ValidationContext'; /** * Unique field definition names @@ -38,9 +38,10 @@ export function UniqueFieldDefinitionNamesRule( }; function checkFieldUniqueness(node: { - +name: NameNode, - +fields?: $ReadOnlyArray, - ... + readonly name: NameNode; + readonly fields?: ReadonlyArray< + InputValueDefinitionNode | FieldDefinitionNode + >; }) { const typeName = node.name.value; diff --git a/src/validation/rules/UniqueFragmentNamesRule.js b/src/validation/rules/UniqueFragmentNamesRule.ts similarity index 86% rename from src/validation/rules/UniqueFragmentNamesRule.js rename to src/validation/rules/UniqueFragmentNamesRule.ts index 144e0e94d5e..8af86b0b83d 100644 --- a/src/validation/rules/UniqueFragmentNamesRule.js +++ b/src/validation/rules/UniqueFragmentNamesRule.ts @@ -1,8 +1,8 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; -import type { ASTValidationContext } from '../ValidationContext'; +import { ASTValidationContext } from '../ValidationContext'; /** * Unique fragment names diff --git a/src/validation/rules/UniqueInputFieldNamesRule.js b/src/validation/rules/UniqueInputFieldNamesRule.ts similarity index 88% rename from src/validation/rules/UniqueInputFieldNamesRule.js rename to src/validation/rules/UniqueInputFieldNamesRule.ts index 413783e9301..afe105d1551 100644 --- a/src/validation/rules/UniqueInputFieldNamesRule.js +++ b/src/validation/rules/UniqueInputFieldNamesRule.ts @@ -1,8 +1,8 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; -import type { ASTValidationContext } from '../ValidationContext'; +import { ASTValidationContext } from '../ValidationContext'; /** * Unique input field names diff --git a/src/validation/rules/UniqueOperationNamesRule.js b/src/validation/rules/UniqueOperationNamesRule.ts similarity index 87% rename from src/validation/rules/UniqueOperationNamesRule.js rename to src/validation/rules/UniqueOperationNamesRule.ts index 6051e919788..7ad12e8a251 100644 --- a/src/validation/rules/UniqueOperationNamesRule.js +++ b/src/validation/rules/UniqueOperationNamesRule.ts @@ -1,8 +1,8 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; +import { ASTVisitor } from '../../language/visitor'; -import type { ASTValidationContext } from '../ValidationContext'; +import { ASTValidationContext } from '../ValidationContext'; /** * Unique operation names diff --git a/src/validation/rules/UniqueOperationTypesRule.js b/src/validation/rules/UniqueOperationTypesRule.ts similarity index 88% rename from src/validation/rules/UniqueOperationTypesRule.js rename to src/validation/rules/UniqueOperationTypesRule.ts index 5b0d2b32cf6..b953f373474 100644 --- a/src/validation/rules/UniqueOperationTypesRule.js +++ b/src/validation/rules/UniqueOperationTypesRule.ts @@ -1,12 +1,9 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; -import type { - SchemaDefinitionNode, - SchemaExtensionNode, -} from '../../language/ast'; +import { ASTVisitor } from '../../language/visitor'; +import { SchemaDefinitionNode, SchemaExtensionNode } from '../../language/ast'; -import type { SDLValidationContext } from '../ValidationContext'; +import { SDLValidationContext } from '../ValidationContext'; /** * Unique operation types diff --git a/src/validation/rules/UniqueTypeNamesRule.js b/src/validation/rules/UniqueTypeNamesRule.ts similarity index 87% rename from src/validation/rules/UniqueTypeNamesRule.js rename to src/validation/rules/UniqueTypeNamesRule.ts index fed280c4463..11cda5549ed 100644 --- a/src/validation/rules/UniqueTypeNamesRule.js +++ b/src/validation/rules/UniqueTypeNamesRule.ts @@ -1,9 +1,9 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; -import type { TypeDefinitionNode } from '../../language/ast'; +import { ASTVisitor } from '../../language/visitor'; +import { TypeDefinitionNode } from '../../language/ast'; -import type { SDLValidationContext } from '../ValidationContext'; +import { SDLValidationContext } from '../ValidationContext'; /** * Unique type names diff --git a/src/validation/rules/UniqueVariableNamesRule.js b/src/validation/rules/UniqueVariableNamesRule.ts similarity index 82% rename from src/validation/rules/UniqueVariableNamesRule.js rename to src/validation/rules/UniqueVariableNamesRule.ts index 6035cdfa3e8..e745a469730 100644 --- a/src/validation/rules/UniqueVariableNamesRule.js +++ b/src/validation/rules/UniqueVariableNamesRule.ts @@ -1,9 +1,9 @@ import { GraphQLError } from '../../error/GraphQLError'; -import type { ASTVisitor } from '../../language/visitor'; -import type { VariableDefinitionNode } from '../../language/ast'; +import { ASTVisitor } from '../../language/visitor'; +import { VariableDefinitionNode } from '../../language/ast'; -import type { ASTValidationContext } from '../ValidationContext'; +import { ASTValidationContext } from '../ValidationContext'; /** * Unique variable names diff --git a/src/validation/rules/ValuesOfCorrectTypeRule.js b/src/validation/rules/ValuesOfCorrectTypeRule.ts similarity index 93% rename from src/validation/rules/ValuesOfCorrectTypeRule.js rename to src/validation/rules/ValuesOfCorrectTypeRule.ts index d97647a0004..878fb11fe66 100644 --- a/src/validation/rules/ValuesOfCorrectTypeRule.js +++ b/src/validation/rules/ValuesOfCorrectTypeRule.ts @@ -7,8 +7,8 @@ import suggestionList from '../../jsutils/suggestionList'; import { GraphQLError } from '../../error/GraphQLError'; -import type { ValueNode } from '../../language/ast'; -import type { ASTVisitor } from '../../language/visitor'; +import { ValueNode } from '../../language/ast'; +import { ASTVisitor } from '../../language/visitor'; import { print } from '../../language/printer'; import { @@ -21,7 +21,7 @@ import { getNamedType, } from '../../type/definition'; -import type { ValidationContext } from '../ValidationContext'; +import { ValidationContext } from '../ValidationContext'; /** * Value literals of correct type @@ -126,7 +126,11 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void { // Scalars and Enums determine if a literal value is valid via parseLiteral(), // which may throw or return an invalid value to indicate failure. try { - const parseResult = type.parseLiteral(node, undefined /* variables */); + const parseResult = type.parseLiteral( + node, + undefined, + /* variables */ + ); if (parseResult === undefined) { const typeStr = inspect(locationType); context.reportError( @@ -149,7 +153,7 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void { undefined, undefined, undefined, - error, // Ensure a reference to the original error is maintained. + error, ), ); } diff --git a/src/validation/rules/VariablesAreInputTypesRule.js b/src/validation/rules/VariablesAreInputTypesRule.ts similarity index 76% rename from src/validation/rules/VariablesAreInputTypesRule.js rename to src/validation/rules/VariablesAreInputTypesRule.ts index f16cb7461d0..52f9d10c6b7 100644 --- a/src/validation/rules/VariablesAreInputTypesRule.js +++ b/src/validation/rules/VariablesAreInputTypesRule.ts @@ -1,14 +1,14 @@ import { GraphQLError } from '../../error/GraphQLError'; import { print } from '../../language/printer'; -import type { ASTVisitor } from '../../language/visitor'; -import type { VariableDefinitionNode } from '../../language/ast'; +import { ASTVisitor } from '../../language/visitor'; +import { VariableDefinitionNode } from '../../language/ast'; import { isInputType } from '../../type/definition'; import { typeFromAST } from '../../utilities/typeFromAST'; -import type { ValidationContext } from '../ValidationContext'; +import { ValidationContext } from '../ValidationContext'; /** * Variables are input types @@ -20,7 +20,9 @@ export function VariablesAreInputTypesRule( context: ValidationContext, ): ASTVisitor { return { - VariableDefinition(node: VariableDefinitionNode): ?GraphQLError { + VariableDefinition( + node: VariableDefinitionNode, + ): GraphQLError | null | undefined { const type = typeFromAST(context.getSchema(), node.type); if (type && !isInputType(type)) { diff --git a/src/validation/rules/VariablesInAllowedPositionRule.js b/src/validation/rules/VariablesInAllowedPositionRule.ts similarity index 89% rename from src/validation/rules/VariablesInAllowedPositionRule.js rename to src/validation/rules/VariablesInAllowedPositionRule.ts index 8d0cbbf26c7..d30ca70557a 100644 --- a/src/validation/rules/VariablesInAllowedPositionRule.js +++ b/src/validation/rules/VariablesInAllowedPositionRule.ts @@ -3,17 +3,17 @@ import inspect from '../../jsutils/inspect'; import { GraphQLError } from '../../error/GraphQLError'; import { Kind } from '../../language/kinds'; -import type { ValueNode } from '../../language/ast'; -import type { ASTVisitor } from '../../language/visitor'; +import { ValueNode } from '../../language/ast'; +import { ASTVisitor } from '../../language/visitor'; -import type { GraphQLSchema } from '../../type/schema'; -import type { GraphQLType } from '../../type/definition'; +import { GraphQLSchema } from '../../type/schema'; +import { GraphQLType } from '../../type/definition'; import { isNonNullType } from '../../type/definition'; import { typeFromAST } from '../../utilities/typeFromAST'; import { isTypeSubTypeOf } from '../../utilities/typeComparators'; -import type { ValidationContext } from '../ValidationContext'; +import { ValidationContext } from '../ValidationContext'; /** * Variables passed to field arguments conform to type @@ -79,9 +79,9 @@ export function VariablesInAllowedPositionRule( function allowedVariableUsage( schema: GraphQLSchema, varType: GraphQLType, - varDefaultValue: ?ValueNode, + varDefaultValue: ValueNode | null | undefined, locationType: GraphQLType, - locationDefaultValue: ?mixed, + locationDefaultValue: unknown | null | undefined, ): boolean { if (isNonNullType(locationType) && !isNonNullType(varType)) { const hasNonNullVariableDefaultValue = diff --git a/src/validation/rules/custom/NoDeprecatedCustomRule.js b/src/validation/rules/custom/NoDeprecatedCustomRule.ts similarity index 96% rename from src/validation/rules/custom/NoDeprecatedCustomRule.js rename to src/validation/rules/custom/NoDeprecatedCustomRule.ts index 7fe6598bc47..2355dbc6f93 100644 --- a/src/validation/rules/custom/NoDeprecatedCustomRule.js +++ b/src/validation/rules/custom/NoDeprecatedCustomRule.ts @@ -2,11 +2,11 @@ import invariant from '../../../jsutils/invariant'; import { GraphQLError } from '../../../error/GraphQLError'; -import type { ASTVisitor } from '../../../language/visitor'; +import { ASTVisitor } from '../../../language/visitor'; import { getNamedType, isInputObjectType } from '../../../type/definition'; -import type { ValidationContext } from '../../ValidationContext'; +import { ValidationContext } from '../../ValidationContext'; /** * No deprecated diff --git a/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.js b/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.ts similarity index 85% rename from src/validation/rules/custom/NoSchemaIntrospectionCustomRule.js rename to src/validation/rules/custom/NoSchemaIntrospectionCustomRule.ts index 7a1c1f2ab9a..a8f7013f748 100644 --- a/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.js +++ b/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.ts @@ -1,12 +1,12 @@ import { GraphQLError } from '../../../error/GraphQLError'; -import type { FieldNode } from '../../../language/ast'; -import type { ASTVisitor } from '../../../language/visitor'; +import { FieldNode } from '../../../language/ast'; +import { ASTVisitor } from '../../../language/visitor'; import { getNamedType } from '../../../type/definition'; import { isIntrospectionType } from '../../../type/introspection'; -import type { ValidationContext } from '../../ValidationContext'; +import { ValidationContext } from '../../ValidationContext'; /** * Prohibit introspection queries diff --git a/src/validation/specifiedRules.js b/src/validation/specifiedRules.ts similarity index 100% rename from src/validation/specifiedRules.js rename to src/validation/specifiedRules.ts diff --git a/src/validation/validate.js b/src/validation/validate.ts similarity index 86% rename from src/validation/validate.js rename to src/validation/validate.ts index 8cb11a5bcd1..e390903bd0d 100644 --- a/src/validation/validate.js +++ b/src/validation/validate.ts @@ -2,15 +2,15 @@ import devAssert from '../jsutils/devAssert'; import { GraphQLError } from '../error/GraphQLError'; -import type { DocumentNode } from '../language/ast'; +import { DocumentNode } from '../language/ast'; import { visit, visitInParallel } from '../language/visitor'; -import type { GraphQLSchema } from '../type/schema'; +import { GraphQLSchema } from '../type/schema'; import { assertValidSchema } from '../type/validate'; import { TypeInfo, visitWithTypeInfo } from '../utilities/TypeInfo'; -import type { SDLValidationRule, ValidationRule } from './ValidationContext'; +import { SDLValidationRule, ValidationRule } from './ValidationContext'; import { specifiedRules, specifiedSDLRules } from './specifiedRules'; import { SDLValidationContext, ValidationContext } from './ValidationContext'; @@ -33,10 +33,10 @@ import { SDLValidationContext, ValidationContext } from './ValidationContext'; export function validate( schema: GraphQLSchema, documentAST: DocumentNode, - rules?: $ReadOnlyArray = specifiedRules, - typeInfo?: TypeInfo = new TypeInfo(schema), - options?: {| maxErrors?: number |} = { maxErrors: undefined }, -): $ReadOnlyArray { + rules: ReadonlyArray = specifiedRules, + typeInfo: TypeInfo = new TypeInfo(schema), + options: { maxErrors?: number } = { maxErrors: undefined }, +): ReadonlyArray { devAssert(documentAST, 'Must provide document.'); // If the schema used for validation is invalid, throw an error. assertValidSchema(schema); @@ -80,9 +80,9 @@ export function validate( */ export function validateSDL( documentAST: DocumentNode, - schemaToExtend?: ?GraphQLSchema, - rules?: $ReadOnlyArray = specifiedSDLRules, -): $ReadOnlyArray { + schemaToExtend?: GraphQLSchema | null | undefined, + rules: ReadonlyArray = specifiedSDLRules, +): ReadonlyArray { const errors = []; const context = new SDLValidationContext( documentAST, diff --git a/src/version.js b/src/version.ts similarity index 100% rename from src/version.js rename to src/version.ts From 6609995fddbf4f2375951875b9297279a4654bed Mon Sep 17 00:00:00 2001 From: Saihajpreet Singh Date: Wed, 18 Nov 2020 09:50:10 -0600 Subject: [PATCH 2/8] convert `+` to `reaadonly` and run prettier --- src/error/GraphQLError.ts | 82 +++-- src/language/ast.ts | 222 +++++++++---- src/type/definition.ts | 666 ++++++++++++++++++++++++++------------ src/type/schema.ts | 6 +- src/type/validate.ts | 385 ++++++++++++++++------ 5 files changed, 966 insertions(+), 395 deletions(-) diff --git a/src/error/GraphQLError.ts b/src/error/GraphQLError.ts index ae25d45ea1b..1cdd9ef74b5 100644 --- a/src/error/GraphQLError.ts +++ b/src/error/GraphQLError.ts @@ -1,13 +1,13 @@ // FIXME: // flowlint uninitialized-instance-property:off -import isObjectLike from "../jsutils/isObjectLike"; +import isObjectLike from '../jsutils/isObjectLike'; -import { ASTNode } from "../language/ast"; -import { Source } from "../language/source"; -import { SourceLocation } from "../language/location"; -import { getLocation } from "../language/location"; -import { printLocation, printSourceLocation } from "../language/printLocation"; +import { ASTNode } from '../language/ast'; +import { Source } from '../language/source'; +import { SourceLocation } from '../language/location'; +import { getLocation } from '../language/location'; +import { printLocation, printSourceLocation } from '../language/printLocation'; /** * A GraphQLError describes an Error found during the parse, validate, or @@ -35,7 +35,7 @@ export class GraphQLError extends Error { * * Enumerable, and appears in the result of JSON.stringify(). */ - +locations: ReadonlyArray | void; + readonly locations: ReadonlyArray | void; /** * An array describing the JSON-path into the execution response which @@ -43,12 +43,12 @@ export class GraphQLError extends Error { * * Enumerable, and appears in the result of JSON.stringify(). */ - +path: ReadonlyArray | void; + readonly path: ReadonlyArray | void; /** * An array of GraphQL AST Nodes corresponding to this error. */ - +nodes: ReadonlyArray | void; + readonly nodes: ReadonlyArray | void; /** * The source GraphQL document for the first location of this error. @@ -56,33 +56,53 @@ export class GraphQLError extends Error { * Note that if this Error represents more than one node, the source may not * represent nodes after the first node. */ - +source: Source | void; + readonly source: Source | void; /** * An array of character offsets within the source GraphQL document * which correspond to this error. */ - +positions: ReadonlyArray | void; + readonly positions: ReadonlyArray | void; /** * The original error thrown from a field resolver during execution. */ - +originalError: Error | null | undefined; + readonly originalError: Error | null | undefined; /** * Extension fields to add to the formatted error. */ - +extensions: { + readonly extensions: { [key: string]: unknown; } | void; - constructor(message: string, nodes?: ReadonlyArray | ASTNode | void | null, source?: Source | null | undefined, positions?: ReadonlyArray | null | undefined, path?: ReadonlyArray | null | undefined, originalError?: (Error & {readonly extensions?: unknown;}) | null | undefined, extensions?: { - [key: string]: unknown; - } | null | undefined): void { + constructor( + message: string, + nodes?: ReadonlyArray | ASTNode | void | null, + source?: Source | null | undefined, + positions?: ReadonlyArray | null | undefined, + path?: ReadonlyArray | null | undefined, + originalError?: + | (Error & { readonly extensions?: unknown }) + | null + | undefined, + extensions?: + | { + [key: string]: unknown; + } + | null + | undefined, + ): void { super(message); // Compute list of blame nodes. - const _nodes = Array.isArray(nodes) ? nodes.length !== 0 ? nodes : undefined : nodes ? [nodes] : undefined; + const _nodes = Array.isArray(nodes) + ? nodes.length !== 0 + ? nodes + : undefined + : nodes + ? [nodes] + : undefined; // Compute locations in the source for the given nodes/positions. let _source = source; @@ -105,7 +125,7 @@ export class GraphQLError extends Error { let _locations; if (positions && source) { - _locations = positions.map(pos => getLocation(source, pos)); + _locations = positions.map((pos) => getLocation(source, pos)); } else if (_nodes) { _locations = _nodes.reduce((list, node) => { if (node.loc) { @@ -123,7 +143,7 @@ export class GraphQLError extends Error { } } - Object.defineProperties((this as any), { + Object.defineProperties(this as any, { name: { value: 'GraphQLError' }, message: { value: message, @@ -131,7 +151,7 @@ export class GraphQLError extends Error { // resulting output. This ensures that the simplest possible GraphQL // service adheres to the spec. enumerable: true, - writable: true + writable: true, }, locations: { // Coercing falsy values to undefined ensures they will not be included @@ -140,7 +160,7 @@ export class GraphQLError extends Error { // By being enumerable, JSON.stringify will include `locations` in the // resulting output. This ensures that the simplest possible GraphQL // service adheres to the spec. - enumerable: _locations != null + enumerable: _locations != null, }, path: { // Coercing falsy values to undefined ensures they will not be included @@ -149,19 +169,19 @@ export class GraphQLError extends Error { // By being enumerable, JSON.stringify will include `path` in the // resulting output. This ensures that the simplest possible GraphQL // service adheres to the spec. - enumerable: path != null + enumerable: path != null, }, nodes: { - value: _nodes ?? undefined + value: _nodes ?? undefined, }, source: { - value: _source ?? undefined + value: _source ?? undefined, }, positions: { - value: _positions ?? undefined + value: _positions ?? undefined, }, originalError: { - value: originalError + value: originalError, }, extensions: { // Coercing falsy values to undefined ensures they will not be included @@ -170,8 +190,8 @@ export class GraphQLError extends Error { // By being enumerable, JSON.stringify will include `path` in the // resulting output. This ensures that the simplest possible GraphQL // service adheres to the spec. - enumerable: _extensions != null - } + enumerable: _extensions != null, + }, }); // Include (non-enumerable) stack trace. @@ -179,7 +199,7 @@ export class GraphQLError extends Error { Object.defineProperty(this, 'stack', { value: originalError.stack, writable: true, - configurable: true + configurable: true, }); return; } @@ -191,7 +211,7 @@ export class GraphQLError extends Error { Object.defineProperty(this, 'stack', { value: Error().stack, writable: true, - configurable: true + configurable: true, }); } } @@ -227,4 +247,4 @@ export function printError(error: GraphQLError): string { } return output; -} \ No newline at end of file +} diff --git a/src/language/ast.ts b/src/language/ast.ts index 162abd8f305..72c2a5322b1 100644 --- a/src/language/ast.ts +++ b/src/language/ast.ts @@ -1,5 +1,5 @@ -import { Source } from "./source"; -import { TokenKindEnum } from "./tokenKind"; +import { Source } from './source'; +import { TokenKindEnum } from './tokenKind'; /** * Contains a range of UTF-8 character offsets and token references that @@ -9,27 +9,27 @@ export class Location { /** * The character offset at which this Node begins. */ - +start: number; + readonly start: number; /** * The character offset at which this Node ends. */ - +end: number; + readonly end: number; /** * The Token at which this Node begins. */ - +startToken: Token; + readonly startToken: Token; /** * The Token at which this Node ends. */ - +endToken: Token; + readonly endToken: Token; /** * The Source document the AST represents. */ - +source: Source; + readonly source: Source; constructor(startToken: Token, endToken: Token, source: Source) { this.start = startToken.start; @@ -39,7 +39,7 @@ export class Location { this.source = source; } - toJSON(): {start: number;end: number;} { + toJSON(): { start: number; end: number } { return { start: this.start, end: this.end }; } @@ -58,42 +58,50 @@ export class Token { /** * The kind of Token. */ - +kind: TokenKindEnum; + readonly kind: TokenKindEnum; /** * The character offset at which this Node begins. */ - +start: number; + readonly start: number; /** * The character offset at which this Node ends. */ - +end: number; + readonly end: number; /** * The 1-indexed line number on which this Token appears. */ - +line: number; + readonly line: number; /** * The 1-indexed column number at which this Token begins. */ - +column: number; + readonly column: number; /** * For non-punctuation tokens, represents the interpreted value of the token. */ - +value: string | void; + readonly value: string | void; /** * Tokens exist as nodes in a double-linked-list amongst all tokens * including ignored tokens. is always the first node and * the last. */ - +prev: Token | null; - +next: Token | null; - - constructor(kind: TokenKindEnum, start: number, end: number, line: number, column: number, prev: Token | null, value?: string) { + readonly prev: Token | null; + readonly next: Token | null; + + constructor( + kind: TokenKindEnum, + start: number, + end: number, + line: number, + column: number, + prev: Token | null, + value?: string, + ) { this.kind = kind; this.start = start; this.end = end; @@ -114,7 +122,7 @@ export class Token { kind: this.kind, value: this.value, line: this.line, - column: this.column + column: this.column, }; } @@ -135,7 +143,50 @@ export function isNode(maybeNode: unknown): boolean { /** * The list of all possible AST node types. */ -export type ASTNode = NameNode | DocumentNode | OperationDefinitionNode | VariableDefinitionNode | VariableNode | SelectionSetNode | FieldNode | ArgumentNode | FragmentSpreadNode | InlineFragmentNode | FragmentDefinitionNode | IntValueNode | FloatValueNode | StringValueNode | BooleanValueNode | NullValueNode | EnumValueNode | ListValueNode | ObjectValueNode | ObjectFieldNode | DirectiveNode | NamedTypeNode | ListTypeNode | NonNullTypeNode | SchemaDefinitionNode | OperationTypeDefinitionNode | ScalarTypeDefinitionNode | ObjectTypeDefinitionNode | FieldDefinitionNode | InputValueDefinitionNode | InterfaceTypeDefinitionNode | UnionTypeDefinitionNode | EnumTypeDefinitionNode | EnumValueDefinitionNode | InputObjectTypeDefinitionNode | DirectiveDefinitionNode | SchemaExtensionNode | ScalarTypeExtensionNode | ObjectTypeExtensionNode | InterfaceTypeExtensionNode | UnionTypeExtensionNode | EnumTypeExtensionNode | InputObjectTypeExtensionNode; +export type ASTNode = + | NameNode + | DocumentNode + | OperationDefinitionNode + | VariableDefinitionNode + | VariableNode + | SelectionSetNode + | FieldNode + | ArgumentNode + | FragmentSpreadNode + | InlineFragmentNode + | FragmentDefinitionNode + | IntValueNode + | FloatValueNode + | StringValueNode + | BooleanValueNode + | NullValueNode + | EnumValueNode + | ListValueNode + | ObjectValueNode + | ObjectFieldNode + | DirectiveNode + | NamedTypeNode + | ListTypeNode + | NonNullTypeNode + | SchemaDefinitionNode + | OperationTypeDefinitionNode + | ScalarTypeDefinitionNode + | ObjectTypeDefinitionNode + | FieldDefinitionNode + | InputValueDefinitionNode + | InterfaceTypeDefinitionNode + | UnionTypeDefinitionNode + | EnumTypeDefinitionNode + | EnumValueDefinitionNode + | InputObjectTypeDefinitionNode + | DirectiveDefinitionNode + | SchemaExtensionNode + | ScalarTypeExtensionNode + | ObjectTypeExtensionNode + | InterfaceTypeExtensionNode + | UnionTypeExtensionNode + | EnumTypeExtensionNode + | InputObjectTypeExtensionNode; /** * Utility type listing all nodes indexed by their kind. @@ -189,7 +240,7 @@ export type ASTKindToNode = { // Name export type NameNode = { - readonly kind: "Name"; + readonly kind: 'Name'; readonly loc?: Location; readonly value: string; }; @@ -197,17 +248,22 @@ export type NameNode = { // Document export type DocumentNode = { - readonly kind: "Document"; + readonly kind: 'Document'; readonly loc?: Location; readonly definitions: ReadonlyArray; }; -export type DefinitionNode = ExecutableDefinitionNode | TypeSystemDefinitionNode | TypeSystemExtensionNode; +export type DefinitionNode = + | ExecutableDefinitionNode + | TypeSystemDefinitionNode + | TypeSystemExtensionNode; -export type ExecutableDefinitionNode = OperationDefinitionNode | FragmentDefinitionNode; +export type ExecutableDefinitionNode = + | OperationDefinitionNode + | FragmentDefinitionNode; export type OperationDefinitionNode = { - readonly kind: "OperationDefinition"; + readonly kind: 'OperationDefinition'; readonly loc?: Location; readonly operation: OperationTypeNode; readonly name?: NameNode; @@ -216,10 +272,10 @@ export type OperationDefinitionNode = { readonly selectionSet: SelectionSetNode; }; -export type OperationTypeNode = "query" | "mutation" | "subscription"; +export type OperationTypeNode = 'query' | 'mutation' | 'subscription'; export type VariableDefinitionNode = { - readonly kind: "VariableDefinition"; + readonly kind: 'VariableDefinition'; readonly loc?: Location; readonly variable: VariableNode; readonly type: TypeNode; @@ -228,13 +284,13 @@ export type VariableDefinitionNode = { }; export type VariableNode = { - readonly kind: "Variable"; + readonly kind: 'Variable'; readonly loc?: Location; readonly name: NameNode; }; export type SelectionSetNode = { - kind: "SelectionSet"; + kind: 'SelectionSet'; loc?: Location; selections: ReadonlyArray; }; @@ -242,7 +298,7 @@ export type SelectionSetNode = { export type SelectionNode = FieldNode | FragmentSpreadNode | InlineFragmentNode; export type FieldNode = { - readonly kind: "Field"; + readonly kind: 'Field'; readonly loc?: Location; readonly alias?: NameNode; readonly name: NameNode; @@ -252,7 +308,7 @@ export type FieldNode = { }; export type ArgumentNode = { - readonly kind: "Argument"; + readonly kind: 'Argument'; readonly loc?: Location; readonly name: NameNode; readonly value: ValueNode; @@ -261,14 +317,14 @@ export type ArgumentNode = { // Fragments export type FragmentSpreadNode = { - readonly kind: "FragmentSpread"; + readonly kind: 'FragmentSpread'; readonly loc?: Location; readonly name: NameNode; readonly directives?: ReadonlyArray; }; export type InlineFragmentNode = { - readonly kind: "InlineFragment"; + readonly kind: 'InlineFragment'; readonly loc?: Location; readonly typeCondition?: NamedTypeNode; readonly directives?: ReadonlyArray; @@ -276,7 +332,7 @@ export type InlineFragmentNode = { }; export type FragmentDefinitionNode = { - readonly kind: "FragmentDefinition"; + readonly kind: 'FragmentDefinition'; readonly loc?: Location; readonly name: NameNode; // Note: fragment variable definitions are experimental and may be changed @@ -289,58 +345,67 @@ export type FragmentDefinitionNode = { // Values -export type ValueNode = VariableNode | IntValueNode | FloatValueNode | StringValueNode | BooleanValueNode | NullValueNode | EnumValueNode | ListValueNode | ObjectValueNode; +export type ValueNode = + | VariableNode + | IntValueNode + | FloatValueNode + | StringValueNode + | BooleanValueNode + | NullValueNode + | EnumValueNode + | ListValueNode + | ObjectValueNode; export type IntValueNode = { - readonly kind: "IntValue"; + readonly kind: 'IntValue'; readonly loc?: Location; readonly value: string; }; export type FloatValueNode = { - readonly kind: "FloatValue"; + readonly kind: 'FloatValue'; readonly loc?: Location; readonly value: string; }; export type StringValueNode = { - readonly kind: "StringValue"; + readonly kind: 'StringValue'; readonly loc?: Location; readonly value: string; readonly block?: boolean; }; export type BooleanValueNode = { - readonly kind: "BooleanValue"; + readonly kind: 'BooleanValue'; readonly loc?: Location; readonly value: boolean; }; export type NullValueNode = { - readonly kind: "NullValue"; + readonly kind: 'NullValue'; readonly loc?: Location; }; export type EnumValueNode = { - readonly kind: "EnumValue"; + readonly kind: 'EnumValue'; readonly loc?: Location; readonly value: string; }; export type ListValueNode = { - readonly kind: "ListValue"; + readonly kind: 'ListValue'; readonly loc?: Location; readonly values: ReadonlyArray; }; export type ObjectValueNode = { - readonly kind: "ObjectValue"; + readonly kind: 'ObjectValue'; readonly loc?: Location; readonly fields: ReadonlyArray; }; export type ObjectFieldNode = { - readonly kind: "ObjectField"; + readonly kind: 'ObjectField'; readonly loc?: Location; readonly name: NameNode; readonly value: ValueNode; @@ -349,7 +414,7 @@ export type ObjectFieldNode = { // Directives export type DirectiveNode = { - readonly kind: "Directive"; + readonly kind: 'Directive'; readonly loc?: Location; readonly name: NameNode; readonly arguments?: ReadonlyArray; @@ -360,29 +425,32 @@ export type DirectiveNode = { export type TypeNode = NamedTypeNode | ListTypeNode | NonNullTypeNode; export type NamedTypeNode = { - readonly kind: "NamedType"; + readonly kind: 'NamedType'; readonly loc?: Location; readonly name: NameNode; }; export type ListTypeNode = { - readonly kind: "ListType"; + readonly kind: 'ListType'; readonly loc?: Location; readonly type: TypeNode; }; export type NonNullTypeNode = { - readonly kind: "NonNullType"; + readonly kind: 'NonNullType'; readonly loc?: Location; readonly type: NamedTypeNode | ListTypeNode; }; // Type System Definition -export type TypeSystemDefinitionNode = SchemaDefinitionNode | TypeDefinitionNode | DirectiveDefinitionNode; +export type TypeSystemDefinitionNode = + | SchemaDefinitionNode + | TypeDefinitionNode + | DirectiveDefinitionNode; export type SchemaDefinitionNode = { - readonly kind: "SchemaDefinition"; + readonly kind: 'SchemaDefinition'; readonly loc?: Location; readonly description?: StringValueNode; readonly directives?: ReadonlyArray; @@ -390,7 +458,7 @@ export type SchemaDefinitionNode = { }; export type OperationTypeDefinitionNode = { - readonly kind: "OperationTypeDefinition"; + readonly kind: 'OperationTypeDefinition'; readonly loc?: Location; readonly operation: OperationTypeNode; readonly type: NamedTypeNode; @@ -398,10 +466,16 @@ export type OperationTypeDefinitionNode = { // Type Definition -export type TypeDefinitionNode = ScalarTypeDefinitionNode | ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode | UnionTypeDefinitionNode | EnumTypeDefinitionNode | InputObjectTypeDefinitionNode; +export type TypeDefinitionNode = + | ScalarTypeDefinitionNode + | ObjectTypeDefinitionNode + | InterfaceTypeDefinitionNode + | UnionTypeDefinitionNode + | EnumTypeDefinitionNode + | InputObjectTypeDefinitionNode; export type ScalarTypeDefinitionNode = { - readonly kind: "ScalarTypeDefinition"; + readonly kind: 'ScalarTypeDefinition'; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; @@ -409,7 +483,7 @@ export type ScalarTypeDefinitionNode = { }; export type ObjectTypeDefinitionNode = { - readonly kind: "ObjectTypeDefinition"; + readonly kind: 'ObjectTypeDefinition'; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; @@ -419,7 +493,7 @@ export type ObjectTypeDefinitionNode = { }; export type FieldDefinitionNode = { - readonly kind: "FieldDefinition"; + readonly kind: 'FieldDefinition'; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; @@ -429,7 +503,7 @@ export type FieldDefinitionNode = { }; export type InputValueDefinitionNode = { - readonly kind: "InputValueDefinition"; + readonly kind: 'InputValueDefinition'; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; @@ -439,7 +513,7 @@ export type InputValueDefinitionNode = { }; export type InterfaceTypeDefinitionNode = { - readonly kind: "InterfaceTypeDefinition"; + readonly kind: 'InterfaceTypeDefinition'; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; @@ -449,7 +523,7 @@ export type InterfaceTypeDefinitionNode = { }; export type UnionTypeDefinitionNode = { - readonly kind: "UnionTypeDefinition"; + readonly kind: 'UnionTypeDefinition'; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; @@ -458,7 +532,7 @@ export type UnionTypeDefinitionNode = { }; export type EnumTypeDefinitionNode = { - readonly kind: "EnumTypeDefinition"; + readonly kind: 'EnumTypeDefinition'; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; @@ -467,7 +541,7 @@ export type EnumTypeDefinitionNode = { }; export type EnumValueDefinitionNode = { - readonly kind: "EnumValueDefinition"; + readonly kind: 'EnumValueDefinition'; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; @@ -475,7 +549,7 @@ export type EnumValueDefinitionNode = { }; export type InputObjectTypeDefinitionNode = { - readonly kind: "InputObjectTypeDefinition"; + readonly kind: 'InputObjectTypeDefinition'; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; @@ -486,7 +560,7 @@ export type InputObjectTypeDefinitionNode = { // Directive Definitions export type DirectiveDefinitionNode = { - readonly kind: "DirectiveDefinition"; + readonly kind: 'DirectiveDefinition'; readonly loc?: Location; readonly description?: StringValueNode; readonly name: NameNode; @@ -500,7 +574,7 @@ export type DirectiveDefinitionNode = { export type TypeSystemExtensionNode = SchemaExtensionNode | TypeExtensionNode; export type SchemaExtensionNode = { - readonly kind: "SchemaExtension"; + readonly kind: 'SchemaExtension'; readonly loc?: Location; readonly directives?: ReadonlyArray; readonly operationTypes?: ReadonlyArray; @@ -508,17 +582,23 @@ export type SchemaExtensionNode = { // Type Extensions -export type TypeExtensionNode = ScalarTypeExtensionNode | ObjectTypeExtensionNode | InterfaceTypeExtensionNode | UnionTypeExtensionNode | EnumTypeExtensionNode | InputObjectTypeExtensionNode; +export type TypeExtensionNode = + | ScalarTypeExtensionNode + | ObjectTypeExtensionNode + | InterfaceTypeExtensionNode + | UnionTypeExtensionNode + | EnumTypeExtensionNode + | InputObjectTypeExtensionNode; export type ScalarTypeExtensionNode = { - readonly kind: "ScalarTypeExtension"; + readonly kind: 'ScalarTypeExtension'; readonly loc?: Location; readonly name: NameNode; readonly directives?: ReadonlyArray; }; export type ObjectTypeExtensionNode = { - readonly kind: "ObjectTypeExtension"; + readonly kind: 'ObjectTypeExtension'; readonly loc?: Location; readonly name: NameNode; readonly interfaces?: ReadonlyArray; @@ -527,7 +607,7 @@ export type ObjectTypeExtensionNode = { }; export type InterfaceTypeExtensionNode = { - readonly kind: "InterfaceTypeExtension"; + readonly kind: 'InterfaceTypeExtension'; readonly loc?: Location; readonly name: NameNode; readonly interfaces?: ReadonlyArray; @@ -536,7 +616,7 @@ export type InterfaceTypeExtensionNode = { }; export type UnionTypeExtensionNode = { - readonly kind: "UnionTypeExtension"; + readonly kind: 'UnionTypeExtension'; readonly loc?: Location; readonly name: NameNode; readonly directives?: ReadonlyArray; @@ -544,7 +624,7 @@ export type UnionTypeExtensionNode = { }; export type EnumTypeExtensionNode = { - readonly kind: "EnumTypeExtension"; + readonly kind: 'EnumTypeExtension'; readonly loc?: Location; readonly name: NameNode; readonly directives?: ReadonlyArray; @@ -552,9 +632,9 @@ export type EnumTypeExtensionNode = { }; export type InputObjectTypeExtensionNode = { - readonly kind: "InputObjectTypeExtension"; + readonly kind: 'InputObjectTypeExtension'; readonly loc?: Location; readonly name: NameNode; readonly directives?: ReadonlyArray; readonly fields?: ReadonlyArray; -}; \ No newline at end of file +}; diff --git a/src/type/definition.ts b/src/type/definition.ts index ccafef7723a..2d5a093e000 100644 --- a/src/type/definition.ts +++ b/src/type/definition.ts @@ -1,40 +1,77 @@ -import { $ReadOnly } from "utility-types"; -import objectEntries from "../polyfills/objectEntries"; - -import { Path } from "../jsutils/Path"; -import { PromiseOrValue } from "../jsutils/PromiseOrValue"; -import { ObjMap, ReadOnlyObjMap, ReadOnlyObjMapLike } from "../jsutils/ObjMap"; -import inspect from "../jsutils/inspect"; -import keyMap from "../jsutils/keyMap"; -import mapValue from "../jsutils/mapValue"; -import toObjMap from "../jsutils/toObjMap"; -import devAssert from "../jsutils/devAssert"; -import keyValMap from "../jsutils/keyValMap"; -import instanceOf from "../jsutils/instanceOf"; -import didYouMean from "../jsutils/didYouMean"; -import isObjectLike from "../jsutils/isObjectLike"; -import identityFunc from "../jsutils/identityFunc"; -import suggestionList from "../jsutils/suggestionList"; - -import { GraphQLError } from "../error/GraphQLError"; - -import { Kind } from "../language/kinds"; -import { print } from "../language/printer"; -import { ScalarTypeDefinitionNode, ObjectTypeDefinitionNode, FieldDefinitionNode, InputValueDefinitionNode, InterfaceTypeDefinitionNode, UnionTypeDefinitionNode, EnumTypeDefinitionNode, EnumValueDefinitionNode, InputObjectTypeDefinitionNode, ScalarTypeExtensionNode, ObjectTypeExtensionNode, InterfaceTypeExtensionNode, UnionTypeExtensionNode, EnumTypeExtensionNode, InputObjectTypeExtensionNode, OperationDefinitionNode, FieldNode, FragmentDefinitionNode, ValueNode } from "../language/ast"; - -import { valueFromASTUntyped } from "../utilities/valueFromASTUntyped"; - -import { GraphQLSchema } from "./schema"; +import { $ReadOnly } from 'utility-types'; +import objectEntries from '../polyfills/objectEntries'; + +import { Path } from '../jsutils/Path'; +import { PromiseOrValue } from '../jsutils/PromiseOrValue'; +import { ObjMap, ReadOnlyObjMap, ReadOnlyObjMapLike } from '../jsutils/ObjMap'; +import inspect from '../jsutils/inspect'; +import keyMap from '../jsutils/keyMap'; +import mapValue from '../jsutils/mapValue'; +import toObjMap from '../jsutils/toObjMap'; +import devAssert from '../jsutils/devAssert'; +import keyValMap from '../jsutils/keyValMap'; +import instanceOf from '../jsutils/instanceOf'; +import didYouMean from '../jsutils/didYouMean'; +import isObjectLike from '../jsutils/isObjectLike'; +import identityFunc from '../jsutils/identityFunc'; +import suggestionList from '../jsutils/suggestionList'; + +import { GraphQLError } from '../error/GraphQLError'; + +import { Kind } from '../language/kinds'; +import { print } from '../language/printer'; +import { + ScalarTypeDefinitionNode, + ObjectTypeDefinitionNode, + FieldDefinitionNode, + InputValueDefinitionNode, + InterfaceTypeDefinitionNode, + UnionTypeDefinitionNode, + EnumTypeDefinitionNode, + EnumValueDefinitionNode, + InputObjectTypeDefinitionNode, + ScalarTypeExtensionNode, + ObjectTypeExtensionNode, + InterfaceTypeExtensionNode, + UnionTypeExtensionNode, + EnumTypeExtensionNode, + InputObjectTypeExtensionNode, + OperationDefinitionNode, + FieldNode, + FragmentDefinitionNode, + ValueNode, +} from '../language/ast'; + +import { valueFromASTUntyped } from '../utilities/valueFromASTUntyped'; + +import { GraphQLSchema } from './schema'; // Predicates & Assertions /** * These are all of the possible kinds of types. */ -export type GraphQLType = GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLInputObjectType | GraphQLList | GraphQLNonNull; +export type GraphQLType = + | GraphQLScalarType + | GraphQLObjectType + | GraphQLInterfaceType + | GraphQLUnionType + | GraphQLEnumType + | GraphQLInputObjectType + | GraphQLList + | GraphQLNonNull; export function isType(type: unknown): boolean { - return (isScalarType(type) || isObjectType(type) || isInterfaceType(type) || isUnionType(type) || isEnumType(type) || isInputObjectType(type) || isListType(type) || isNonNullType(type)); + return ( + isScalarType(type) || + isObjectType(type) || + isInterfaceType(type) || + isUnionType(type) || + isEnumType(type) || + isInputObjectType(type) || + isListType(type) || + isNonNullType(type) + ); } export function assertType(type: unknown): GraphQLType { @@ -81,7 +118,9 @@ export function isInterfaceType(type) { export function assertInterfaceType(type: unknown): GraphQLInterfaceType { if (!isInterfaceType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL Interface type.`); + throw new Error( + `Expected ${inspect(type)} to be a GraphQL Interface type.`, + ); } return type; } @@ -120,7 +159,9 @@ export function isInputObjectType(type) { export function assertInputObjectType(type: unknown): GraphQLInputObjectType { if (!isInputObjectType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL Input Object type.`); + throw new Error( + `Expected ${inspect(type)} to be a GraphQL Input Object type.`, + ); } return type; } @@ -154,10 +195,25 @@ export function assertNonNullType(type: unknown): GraphQLNonNull { /** * These types may be used as input types for arguments and directives. */ -export type GraphQLInputType = GraphQLScalarType | GraphQLEnumType | GraphQLInputObjectType | GraphQLList | GraphQLNonNull>; +export type GraphQLInputType = + | GraphQLScalarType + | GraphQLEnumType + | GraphQLInputObjectType + | GraphQLList + | GraphQLNonNull< + | GraphQLScalarType + | GraphQLEnumType + | GraphQLInputObjectType + | GraphQLList + >; export function isInputType(type: unknown): boolean { - return (isScalarType(type) || isEnumType(type) || isInputObjectType(type) || (isWrappingType(type) && isInputType(type.ofType))); + return ( + isScalarType(type) || + isEnumType(type) || + isInputObjectType(type) || + (isWrappingType(type) && isInputType(type.ofType)) + ); } export function assertInputType(type: unknown): GraphQLInputType { @@ -170,10 +226,31 @@ export function assertInputType(type: unknown): GraphQLInputType { /** * These types may be used as output types as the result of fields. */ -export type GraphQLOutputType = GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLList | GraphQLNonNull>; +export type GraphQLOutputType = + | GraphQLScalarType + | GraphQLObjectType + | GraphQLInterfaceType + | GraphQLUnionType + | GraphQLEnumType + | GraphQLList + | GraphQLNonNull< + | GraphQLScalarType + | GraphQLObjectType + | GraphQLInterfaceType + | GraphQLUnionType + | GraphQLEnumType + | GraphQLList + >; export function isOutputType(type: unknown): boolean { - return (isScalarType(type) || isObjectType(type) || isInterfaceType(type) || isUnionType(type) || isEnumType(type) || (isWrappingType(type) && isOutputType(type.ofType))); + return ( + isScalarType(type) || + isObjectType(type) || + isInterfaceType(type) || + isUnionType(type) || + isEnumType(type) || + (isWrappingType(type) && isOutputType(type.ofType)) + ); } export function assertOutputType(type: unknown): GraphQLOutputType { @@ -202,7 +279,10 @@ export function assertLeafType(type: unknown): GraphQLLeafType { /** * These types may describe the parent context of a selection set. */ -export type GraphQLCompositeType = GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType; +export type GraphQLCompositeType = + | GraphQLObjectType + | GraphQLInterfaceType + | GraphQLUnionType; export function isCompositeType(type: unknown): boolean { return isObjectType(type) || isInterfaceType(type) || isUnionType(type); @@ -210,7 +290,9 @@ export function isCompositeType(type: unknown): boolean { export function assertCompositeType(type: unknown): GraphQLCompositeType { if (!isCompositeType(type)) { - throw new Error(`Expected ${inspect(type)} to be a GraphQL composite type.`); + throw new Error( + `Expected ${inspect(type)} to be a GraphQL composite type.`, + ); } return type; } @@ -250,11 +332,13 @@ export function assertAbstractType(type: unknown): GraphQLAbstractType { * */ export class GraphQLList { - - +ofType: T; + readonly ofType: T; constructor(ofType: T) { - devAssert(isType(ofType), `Expected ${inspect(ofType)} to be a GraphQL type.`); + devAssert( + isType(ofType), + `Expected ${inspect(ofType)} to be a GraphQL type.`, + ); this.ofType = ofType; } @@ -294,11 +378,13 @@ export class GraphQLList { * Note: the enforcement of non-nullability occurs within the executor. */ export class GraphQLNonNull { - - +ofType: T; + readonly ofType: T; constructor(ofType: T) { - devAssert(isNullableType(ofType), `Expected ${inspect(ofType)} to be a GraphQL nullable type.`); + devAssert( + isNullableType(ofType), + `Expected ${inspect(ofType)} to be a GraphQL nullable type.`, + ); this.ofType = ofType; } @@ -336,7 +422,14 @@ export function assertWrappingType(type: unknown): GraphQLWrappingType { /** * These types can all accept null as a value. */ -export type GraphQLNullableType = GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLInputObjectType | GraphQLList; +export type GraphQLNullableType = + | GraphQLScalarType + | GraphQLObjectType + | GraphQLInterfaceType + | GraphQLUnionType + | GraphQLEnumType + | GraphQLInputObjectType + | GraphQLList; export function isNullableType(type: unknown): boolean { return isType(type) && !isNonNullType(type); @@ -363,10 +456,23 @@ export function getNullableType(type) { /** * These named types do not include modifiers like List or NonNull. */ -export type GraphQLNamedType = GraphQLScalarType | GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLEnumType | GraphQLInputObjectType; +export type GraphQLNamedType = + | GraphQLScalarType + | GraphQLObjectType + | GraphQLInterfaceType + | GraphQLUnionType + | GraphQLEnumType + | GraphQLInputObjectType; export function isNamedType(type: unknown): boolean { - return (isScalarType(type) || isObjectType(type) || isInterfaceType(type) || isUnionType(type) || isEnumType(type) || isInputObjectType(type)); + return ( + isScalarType(type) || + isObjectType(type) || + isInterfaceType(type) || + isUnionType(type) || + isEnumType(type) || + isInputObjectType(type) + ); } export function assertNamedType(type: unknown): GraphQLNamedType { @@ -401,7 +507,9 @@ function resolveThunk(thunk: Thunk): T { return typeof thunk === 'function' ? thunk() : thunk; } -function undefineIfEmpty(arr: ReadonlyArray | null | undefined): ReadonlyArray | null | undefined { +function undefineIfEmpty( + arr: ReadonlyArray | null | undefined, +): ReadonlyArray | null | undefined { return arr && arr.length > 0 ? arr : undefined; } @@ -430,7 +538,6 @@ function undefineIfEmpty(arr: ReadonlyArray | null | undefined): ReadonlyA * */ export class GraphQLScalarType { - name: string; description: string | null | undefined; specifiedByUrl: string | null | undefined; @@ -441,26 +548,42 @@ export class GraphQLScalarType { astNode: ScalarTypeDefinitionNode | null | undefined; extensionASTNodes: ReadonlyArray | null | undefined; - constructor(config: $ReadOnly>): void { + constructor( + config: $ReadOnly>, + ): void { const parseValue = config.parseValue ?? identityFunc; this.name = config.name; this.description = config.description; this.specifiedByUrl = config.specifiedByUrl; this.serialize = config.serialize ?? identityFunc; this.parseValue = parseValue; - this.parseLiteral = config.parseLiteral ?? ((node, variables) => parseValue(valueFromASTUntyped(node, variables))); + this.parseLiteral = + config.parseLiteral ?? + ((node, variables) => parseValue(valueFromASTUntyped(node, variables))); this.extensions = config.extensions && toObjMap(config.extensions); this.astNode = config.astNode; this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); devAssert(typeof config.name === 'string', 'Must provide name.'); - devAssert(config.specifiedByUrl == null || typeof config.specifiedByUrl === 'string', `${this.name} must provide "specifiedByUrl" as a string, ` + `but got: ${inspect(config.specifiedByUrl)}.`); + devAssert( + config.specifiedByUrl == null || + typeof config.specifiedByUrl === 'string', + `${this.name} must provide "specifiedByUrl" as a string, ` + + `but got: ${inspect(config.specifiedByUrl)}.`, + ); - devAssert(config.serialize == null || typeof config.serialize === 'function', `${this.name} must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.`); + devAssert( + config.serialize == null || typeof config.serialize === 'function', + `${this.name} must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.`, + ); if (config.parseLiteral) { - devAssert(typeof config.parseValue === 'function' && typeof config.parseLiteral === 'function', `${this.name} must provide both "parseValue" and "parseLiteral" functions.`); + devAssert( + typeof config.parseValue === 'function' && + typeof config.parseLiteral === 'function', + `${this.name} must provide both "parseValue" and "parseLiteral" functions.`, + ); } } @@ -480,7 +603,7 @@ export class GraphQLScalarType { parseLiteral: this.parseLiteral, extensions: this.extensions, astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [] + extensionASTNodes: this.extensionASTNodes ?? [], }; } @@ -498,11 +621,18 @@ export class GraphQLScalarType { } } -export type GraphQLScalarSerializer = (outputValue: unknown) => TExternal | null | undefined; +export type GraphQLScalarSerializer = ( + outputValue: unknown, +) => TExternal | null | undefined; -export type GraphQLScalarValueParser = (inputValue: unknown) => TInternal | null | undefined; +export type GraphQLScalarValueParser = ( + inputValue: unknown, +) => TInternal | null | undefined; -export type GraphQLScalarLiteralParser = (valueNode: ValueNode, variables: ObjMap | null | undefined) => TInternal | null | undefined; +export type GraphQLScalarLiteralParser = ( + valueNode: ValueNode, + variables: ObjMap | null | undefined, +) => TInternal | null | undefined; export type GraphQLScalarTypeConfig = { name: string; @@ -557,7 +687,6 @@ export type GraphQLScalarTypeConfig = { * */ export class GraphQLObjectType { - name: string; description: string | null | undefined; isTypeOf: GraphQLIsTypeOfFn | null | undefined; @@ -579,7 +708,11 @@ export class GraphQLObjectType { this._fields = defineFieldMap.bind(undefined, config); this._interfaces = defineInterfaces.bind(undefined, config); devAssert(typeof config.name === 'string', 'Must provide name.'); - devAssert(config.isTypeOf == null || typeof config.isTypeOf === 'function', `${this.name} must provide "isTypeOf" as a function, ` + `but got: ${inspect(config.isTypeOf)}.`); + devAssert( + config.isTypeOf == null || typeof config.isTypeOf === 'function', + `${this.name} must provide "isTypeOf" as a function, ` + + `but got: ${inspect(config.isTypeOf)}.`, + ); } getFields(): GraphQLFieldMap { @@ -610,7 +743,7 @@ export class GraphQLObjectType { isTypeOf: this.isTypeOf, extensions: this.extensions, astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes || [] + extensionASTNodes: this.extensionASTNodes || [], }; } @@ -628,22 +761,48 @@ export class GraphQLObjectType { } } -function defineInterfaces(config: $ReadOnly | GraphQLInterfaceTypeConfig>): Array { +function defineInterfaces( + config: $ReadOnly< + | GraphQLObjectTypeConfig + | GraphQLInterfaceTypeConfig + >, +): Array { const interfaces = resolveThunk(config.interfaces) ?? []; - devAssert(Array.isArray(interfaces), `${config.name} interfaces must be an Array or a function which returns an Array.`); + devAssert( + Array.isArray(interfaces), + `${config.name} interfaces must be an Array or a function which returns an Array.`, + ); return interfaces; } -function defineFieldMap(config: $ReadOnly | GraphQLInterfaceTypeConfig>): GraphQLFieldMap { +function defineFieldMap( + config: $ReadOnly< + | GraphQLObjectTypeConfig + | GraphQLInterfaceTypeConfig + >, +): GraphQLFieldMap { const fieldMap = resolveThunk(config.fields); - devAssert(isPlainObj(fieldMap), `${config.name} fields must be an object with field names as keys or a function which returns such an object.`); + devAssert( + isPlainObj(fieldMap), + `${config.name} fields must be an object with field names as keys or a function which returns such an object.`, + ); return mapValue(fieldMap, (fieldConfig, fieldName) => { - devAssert(isPlainObj(fieldConfig), `${config.name}.${fieldName} field config must be an object.`); - devAssert(fieldConfig.resolve == null || typeof fieldConfig.resolve === 'function', `${config.name}.${fieldName} field resolver must be a function if ` + `provided, but got: ${inspect(fieldConfig.resolve)}.`); + devAssert( + isPlainObj(fieldConfig), + `${config.name}.${fieldName} field config must be an object.`, + ); + devAssert( + fieldConfig.resolve == null || typeof fieldConfig.resolve === 'function', + `${config.name}.${fieldName} field resolver must be a function if ` + + `provided, but got: ${inspect(fieldConfig.resolve)}.`, + ); const argsConfig = fieldConfig.args ?? {}; - devAssert(isPlainObj(argsConfig), `${config.name}.${fieldName} args must be an object with argument names as keys.`); + devAssert( + isPlainObj(argsConfig), + `${config.name}.${fieldName} args must be an object with argument names as keys.`, + ); const args = objectEntries(argsConfig).map(([argName, argConfig]) => ({ name: argName, @@ -652,7 +811,7 @@ function defineFieldMap(config: $ReadOnly(config: $ReadOnly): GraphQLFieldConfigMap { - return mapValue(fields, field => ({ +function fieldsToFieldsConfig( + fields: GraphQLFieldMap, +): GraphQLFieldConfigMap { + return mapValue(fields, (field) => ({ description: field.description, type: field.type, args: argsToArgsConfig(field.args), @@ -682,22 +843,28 @@ function fieldsToFieldsConfig(fields: GraphQLFieldMap): GraphQ subscribe: field.subscribe, deprecationReason: field.deprecationReason, extensions: field.extensions, - astNode: field.astNode + astNode: field.astNode, })); } /** * @internal */ -export function argsToArgsConfig(args: ReadonlyArray): GraphQLFieldConfigArgumentMap { - return keyValMap(args, arg => arg.name, arg => ({ - description: arg.description, - type: arg.type, - defaultValue: arg.defaultValue, - deprecationReason: arg.deprecationReason, - extensions: arg.extensions, - astNode: arg.astNode - })); +export function argsToArgsConfig( + args: ReadonlyArray, +): GraphQLFieldConfigArgumentMap { + return keyValMap( + args, + (arg) => arg.name, + (arg) => ({ + description: arg.description, + type: arg.type, + defaultValue: arg.defaultValue, + deprecationReason: arg.deprecationReason, + extensions: arg.extensions, + astNode: arg.astNode, + }), + ); } export type GraphQLObjectTypeConfig = { @@ -714,13 +881,31 @@ export type GraphQLObjectTypeConfig = { /** * Note: returning GraphQLObjectType is deprecated and will be removed in v16.0.0 */ -export type GraphQLTypeResolver = (value: TSource, context: TContext, info: GraphQLResolveInfo, abstractType: GraphQLAbstractType) => PromiseOrValue; - -export type GraphQLIsTypeOfFn = (source: TSource, context: TContext, info: GraphQLResolveInfo) => PromiseOrValue; - -export type GraphQLFieldResolver = (source: TSource, args: TArgs, context: TContext, info: GraphQLResolveInfo) => unknown; +export type GraphQLTypeResolver = ( + value: TSource, + context: TContext, + info: GraphQLResolveInfo, + abstractType: GraphQLAbstractType, +) => PromiseOrValue; + +export type GraphQLIsTypeOfFn = ( + source: TSource, + context: TContext, + info: GraphQLResolveInfo, +) => PromiseOrValue; + +export type GraphQLFieldResolver< + TSource, + TContext, + TArgs = { + [argument: string]: any; + } +> = ( + source: TSource, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo, +) => unknown; export type GraphQLResolveInfo = { readonly fieldName: string; @@ -737,9 +922,13 @@ export type GraphQLResolveInfo = { }; }; -export type GraphQLFieldConfig = { +export type GraphQLFieldConfig< + TSource, + TContext, + TArgs = { + [argument: string]: any; + } +> = { description?: string | null | undefined; type: GraphQLOutputType; args?: GraphQLFieldConfigArgumentMap; @@ -761,11 +950,17 @@ export type GraphQLArgumentConfig = { astNode?: InputValueDefinitionNode | null | undefined; }; -export type GraphQLFieldConfigMap = ObjMap>; +export type GraphQLFieldConfigMap = ObjMap< + GraphQLFieldConfig +>; -export type GraphQLField = { +export type GraphQLField< + TSource, + TContext, + TArgs = { + [argument: string]: any; + } +> = { name: string; description: string | null | undefined; type: GraphQLOutputType; @@ -791,7 +986,9 @@ export function isRequiredArgument(arg: GraphQLArgument): boolean { return isNonNullType(arg.type) && arg.defaultValue === undefined; } -export type GraphQLFieldMap = ObjMap>; +export type GraphQLFieldMap = ObjMap< + GraphQLField +>; /** * Interface Type Definition @@ -812,13 +1009,15 @@ export type GraphQLFieldMap = ObjMap | null | undefined; extensions: ReadOnlyObjMap | null | undefined; astNode: InterfaceTypeDefinitionNode | null | undefined; - extensionASTNodes: ReadonlyArray | null | undefined; + extensionASTNodes: + | ReadonlyArray + | null + | undefined; _fields: Thunk>; _interfaces: Thunk>; @@ -834,7 +1033,11 @@ export class GraphQLInterfaceType { this._fields = defineFieldMap.bind(undefined, config); this._interfaces = defineInterfaces.bind(undefined, config); devAssert(typeof config.name === 'string', 'Must provide name.'); - devAssert(config.resolveType == null || typeof config.resolveType === 'function', `${this.name} must provide "resolveType" as a function, ` + `but got: ${inspect(config.resolveType)}.`); + devAssert( + config.resolveType == null || typeof config.resolveType === 'function', + `${this.name} must provide "resolveType" as a function, ` + + `but got: ${inspect(config.resolveType)}.`, + ); } getFields(): GraphQLFieldMap { @@ -865,7 +1068,7 @@ export class GraphQLInterfaceType { resolveType: this.resolveType, extensions: this.extensions, astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [] + extensionASTNodes: this.extensionASTNodes ?? [], }; } @@ -897,7 +1100,10 @@ export type GraphQLInterfaceTypeConfig = { resolveType?: GraphQLTypeResolver | null | undefined; extensions?: ReadOnlyObjMapLike | null | undefined; astNode?: InterfaceTypeDefinitionNode | null | undefined; - extensionASTNodes?: ReadonlyArray | null | undefined; + extensionASTNodes?: + | ReadonlyArray + | null + | undefined; }; /** @@ -924,7 +1130,6 @@ export type GraphQLInterfaceTypeConfig = { * */ export class GraphQLUnionType { - name: string; description: string | null | undefined; resolveType: GraphQLTypeResolver | null | undefined; @@ -944,7 +1149,11 @@ export class GraphQLUnionType { this._types = defineTypes.bind(undefined, config); devAssert(typeof config.name === 'string', 'Must provide name.'); - devAssert(config.resolveType == null || typeof config.resolveType === 'function', `${this.name} must provide "resolveType" as a function, ` + `but got: ${inspect(config.resolveType)}.`); + devAssert( + config.resolveType == null || typeof config.resolveType === 'function', + `${this.name} must provide "resolveType" as a function, ` + + `but got: ${inspect(config.resolveType)}.`, + ); } getTypes(): Array { @@ -966,7 +1175,7 @@ export class GraphQLUnionType { resolveType: this.resolveType, extensions: this.extensions, astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [] + extensionASTNodes: this.extensionASTNodes ?? [], }; } @@ -984,9 +1193,14 @@ export class GraphQLUnionType { } } -function defineTypes(config: $ReadOnly>): Array { +function defineTypes( + config: $ReadOnly>, +): Array { const types = resolveThunk(config.types); - devAssert(Array.isArray(types), `Must provide Array of types or a function which returns such an array for Union ${config.name}.`); + devAssert( + Array.isArray(types), + `Must provide Array of types or a function which returns such an array for Union ${config.name}.`, + ); return types; } @@ -1027,27 +1241,31 @@ export type GraphQLUnionTypeConfig = { * Note: If a value is not provided in a definition, the name of the enum value * will be used as its internal value. */ -export class GraphQLEnumType -/* */ -{ - +export class GraphQLEnumType { + /* */ name: string; description: string | null | undefined; extensions: ReadOnlyObjMap | null | undefined; astNode: EnumTypeDefinitionNode | null | undefined; extensionASTNodes: ReadonlyArray | null | undefined; - _values: Array */ + _values: Array< + GraphQLEnumValue + /* */ + >; + _valueLookup: Map< + any, + /* T */ + GraphQLEnumValue >; - _valueLookup: Map; _nameLookup: ObjMap; - constructor(config: $ReadOnly */ - >): void { + constructor( + config: $ReadOnly< + GraphQLEnumTypeConfig + /* */ + >, + ): void { this.name = config.name; this.description = config.description; this.extensions = config.extensions && toObjMap(config.extensions); @@ -1055,14 +1273,17 @@ export class GraphQLEnumType this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes); this._values = defineEnumValues(this.name, config.values); - this._valueLookup = new Map(this._values.map(enumValue => [enumValue.value, enumValue])); - this._nameLookup = keyMap(this._values, value => value.name); + this._valueLookup = new Map( + this._values.map((enumValue) => [enumValue.value, enumValue]), + ); + this._nameLookup = keyMap(this._values, (value) => value.name); devAssert(typeof config.name === 'string', 'Must provide name.'); } - getValues(): Array */ + getValues(): Array< + GraphQLEnumValue + /* */ > { return this._values; } @@ -1071,44 +1292,60 @@ export class GraphQLEnumType return this._nameLookup[name]; } - serialize(outputValue: unknown - /* T */ + serialize( + outputValue: unknown, + /* T */ ): string | null | undefined { const enumValue = this._valueLookup.get(outputValue); if (enumValue === undefined) { - throw new GraphQLError(`Enum "${this.name}" cannot represent value: ${inspect(outputValue)}`); + throw new GraphQLError( + `Enum "${this.name}" cannot represent value: ${inspect(outputValue)}`, + ); } return enumValue.name; } - parseValue(inputValue: unknown): any | null | undefined - /* T */ - { + parseValue(inputValue: unknown): any | null | undefined /* T */ { if (typeof inputValue !== 'string') { const valueStr = inspect(inputValue); - throw new GraphQLError(`Enum "${this.name}" cannot represent non-string value: ${valueStr}.` + didYouMeanEnumValue(this, valueStr)); + throw new GraphQLError( + `Enum "${this.name}" cannot represent non-string value: ${valueStr}.` + + didYouMeanEnumValue(this, valueStr), + ); } const enumValue = this.getValue(inputValue); if (enumValue == null) { - throw new GraphQLError(`Value "${inputValue}" does not exist in "${this.name}" enum.` + didYouMeanEnumValue(this, inputValue)); + throw new GraphQLError( + `Value "${inputValue}" does not exist in "${this.name}" enum.` + + didYouMeanEnumValue(this, inputValue), + ); } return enumValue.value; } - parseLiteral(valueNode: ValueNode, _variables: ObjMap | null | undefined): any | null | undefined - /* T */ - { + parseLiteral( + valueNode: ValueNode, + _variables: ObjMap | null | undefined, + ): any | null | undefined /* T */ { // Note: variables will be resolved to a value before calling this function. if (valueNode.kind !== Kind.ENUM) { const valueStr = print(valueNode); - throw new GraphQLError(`Enum "${this.name}" cannot represent non-enum value: ${valueStr}.` + didYouMeanEnumValue(this, valueStr), valueNode); + throw new GraphQLError( + `Enum "${this.name}" cannot represent non-enum value: ${valueStr}.` + + didYouMeanEnumValue(this, valueStr), + valueNode, + ); } const enumValue = this.getValue(valueNode.value); if (enumValue == null) { const valueStr = print(valueNode); - throw new GraphQLError(`Value "${valueStr}" does not exist in "${this.name}" enum.` + didYouMeanEnumValue(this, valueStr), valueNode); + throw new GraphQLError( + `Value "${valueStr}" does not exist in "${this.name}" enum.` + + didYouMeanEnumValue(this, valueStr), + valueNode, + ); } return enumValue.value; } @@ -1117,13 +1354,17 @@ export class GraphQLEnumType extensions: ReadOnlyObjMap | null | undefined; extensionASTNodes: ReadonlyArray; } { - const values = keyValMap(this.getValues(), value => value.name, value => ({ - description: value.description, - value: value.value, - deprecationReason: value.deprecationReason, - extensions: value.extensions, - astNode: value.astNode - })); + const values = keyValMap( + this.getValues(), + (value) => value.name, + (value) => ({ + description: value.description, + value: value.value, + deprecationReason: value.deprecationReason, + extensions: value.extensions, + astNode: value.astNode, + }), + ); return { name: this.name, @@ -1131,7 +1372,7 @@ export class GraphQLEnumType values, extensions: this.extensions, astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [] + extensionASTNodes: this.extensionASTNodes ?? [], }; } @@ -1149,71 +1390,85 @@ export class GraphQLEnumType } } -function didYouMeanEnumValue(enumType: GraphQLEnumType, unknownValueStr: string): string { - const allNames = enumType.getValues().map(value => value.name); +function didYouMeanEnumValue( + enumType: GraphQLEnumType, + unknownValueStr: string, +): string { + const allNames = enumType.getValues().map((value) => value.name); const suggestedValues = suggestionList(unknownValueStr, allNames); return didYouMean('the enum value', suggestedValues); } -function defineEnumValues(typeName: string, valueMap: GraphQLEnumValueConfigMap -/* */ -): Array */ +function defineEnumValues( + typeName: string, + valueMap: GraphQLEnumValueConfigMap, + /* */ +): Array< + GraphQLEnumValue + /* */ > { - devAssert(isPlainObj(valueMap), `${typeName} values must be an object with value names as keys.`); + devAssert( + isPlainObj(valueMap), + `${typeName} values must be an object with value names as keys.`, + ); return objectEntries(valueMap).map(([valueName, valueConfig]) => { - devAssert(isPlainObj(valueConfig), `${typeName}.${valueName} must refer to an object with a "value" key ` + `representing an internal value but got: ${inspect(valueConfig)}.`); + devAssert( + isPlainObj(valueConfig), + `${typeName}.${valueName} must refer to an object with a "value" key ` + + `representing an internal value but got: ${inspect(valueConfig)}.`, + ); return { name: valueName, description: valueConfig.description, value: valueConfig.value !== undefined ? valueConfig.value : valueName, deprecationReason: valueConfig.deprecationReason, extensions: valueConfig.extensions && toObjMap(valueConfig.extensions), - astNode: valueConfig.astNode + astNode: valueConfig.astNode, }; }); } -export type GraphQLEnumTypeConfig -/* */ -= { - name: string; - description?: string | null | undefined; - values: GraphQLEnumValueConfigMap; +export type GraphQLEnumTypeConfig = /* */ - extensions?: ReadOnlyObjMapLike | null | undefined; - astNode?: EnumTypeDefinitionNode | null | undefined; - extensionASTNodes?: ReadonlyArray | null | undefined; -}; + { + name: string; + description?: string | null | undefined; + values: GraphQLEnumValueConfigMap; + /* */ + extensions?: ReadOnlyObjMapLike | null | undefined; + astNode?: EnumTypeDefinitionNode | null | undefined; + extensionASTNodes?: ReadonlyArray | null | undefined; + }; -export type GraphQLEnumValueConfigMap -/* */ -= ObjMap */ ->; -export type GraphQLEnumValueConfig -/* */ -= { - description?: string | null | undefined; - value?: any; - /* T */ - deprecationReason?: string | null | undefined; - extensions?: ReadOnlyObjMapLike | null | undefined; - astNode?: EnumValueDefinitionNode | null | undefined; -}; +export type GraphQLEnumValueConfigMap = + /* */ + ObjMap< + GraphQLEnumValueConfig + /* */ + >; +export type GraphQLEnumValueConfig = + /* */ + { + description?: string | null | undefined; + value?: any; + /* T */ + deprecationReason?: string | null | undefined; + extensions?: ReadOnlyObjMapLike | null | undefined; + astNode?: EnumValueDefinitionNode | null | undefined; + }; -export type GraphQLEnumValue -/* */ -= { - name: string; - description: string | null | undefined; - value: any; - /* T */ - deprecationReason: string | null | undefined; - extensions: ReadOnlyObjMap | null | undefined; - astNode: EnumValueDefinitionNode | null | undefined; -}; +export type GraphQLEnumValue = + /* */ + { + name: string; + description: string | null | undefined; + value: any; + /* T */ + deprecationReason: string | null | undefined; + extensions: ReadOnlyObjMap | null | undefined; + astNode: EnumValueDefinitionNode | null | undefined; + }; /** * Input Object Type Definition @@ -1236,12 +1491,14 @@ export type GraphQLEnumValue * */ export class GraphQLInputObjectType { - name: string; description: string | null | undefined; extensions: ReadOnlyObjMap | null | undefined; astNode: InputObjectTypeDefinitionNode | null | undefined; - extensionASTNodes: ReadonlyArray | null | undefined; + extensionASTNodes: + | ReadonlyArray + | null + | undefined; _fields: Thunk; @@ -1268,12 +1525,12 @@ export class GraphQLInputObjectType { extensions: ReadOnlyObjMap | null | undefined; extensionASTNodes: ReadonlyArray; } { - const fields = mapValue(this.getFields(), field => ({ + const fields = mapValue(this.getFields(), (field) => ({ description: field.description, type: field.type, defaultValue: field.defaultValue, extensions: field.extensions, - astNode: field.astNode + astNode: field.astNode, })); return { @@ -1282,7 +1539,7 @@ export class GraphQLInputObjectType { fields, extensions: this.extensions, astNode: this.astNode, - extensionASTNodes: this.extensionASTNodes ?? [] + extensionASTNodes: this.extensionASTNodes ?? [], }; } @@ -1300,11 +1557,19 @@ export class GraphQLInputObjectType { } } -function defineInputFieldMap(config: $ReadOnly): GraphQLInputFieldMap { +function defineInputFieldMap( + config: $ReadOnly, +): GraphQLInputFieldMap { const fieldMap = resolveThunk(config.fields); - devAssert(isPlainObj(fieldMap), `${config.name} fields must be an object with field names as keys or a function which returns such an object.`); + devAssert( + isPlainObj(fieldMap), + `${config.name} fields must be an object with field names as keys or a function which returns such an object.`, + ); return mapValue(fieldMap, (fieldConfig, fieldName) => { - devAssert(!('resolve' in fieldConfig), `${config.name}.${fieldName} field has a resolve property, but Input Types cannot define resolvers.`); + devAssert( + !('resolve' in fieldConfig), + `${config.name}.${fieldName} field has a resolve property, but Input Types cannot define resolvers.`, + ); return { name: fieldName, @@ -1313,7 +1578,7 @@ function defineInputFieldMap(config: $ReadOnly): G defaultValue: fieldConfig.defaultValue, deprecationReason: fieldConfig.deprecationReason, extensions: fieldConfig.extensions && toObjMap(fieldConfig.extensions), - astNode: fieldConfig.astNode + astNode: fieldConfig.astNode, }; }); } @@ -1324,7 +1589,10 @@ export type GraphQLInputObjectTypeConfig = { fields: Thunk; extensions?: ReadOnlyObjMapLike | null | undefined; astNode?: InputObjectTypeDefinitionNode | null | undefined; - extensionASTNodes?: ReadonlyArray | null | undefined; + extensionASTNodes?: + | ReadonlyArray + | null + | undefined; }; export type GraphQLInputFieldConfig = { @@ -1352,4 +1620,4 @@ export function isRequiredInputField(field: GraphQLInputField): boolean { return isNonNullType(field.type) && field.defaultValue === undefined; } -export type GraphQLInputFieldMap = ObjMap; \ No newline at end of file +export type GraphQLInputFieldMap = ObjMap; diff --git a/src/type/schema.ts b/src/type/schema.ts index d7a46392d04..93c7cae1ce6 100644 --- a/src/type/schema.ts +++ b/src/type/schema.ts @@ -280,10 +280,8 @@ export class GraphQLSchema { getImplementations( interfaceType: GraphQLInterfaceType, ): { - objects: /* $ReadOnly */ - Array; - interfaces: /* $ReadOnly */ - Array; + objects: /* $ReadOnly */ Array; + interfaces: /* $ReadOnly */ Array; } { const implementations = this._implementationsMap[interfaceType.name]; return implementations ?? { objects: [], interfaces: [] }; diff --git a/src/type/validate.ts b/src/type/validate.ts index 604862c121f..213ef214442 100644 --- a/src/type/validate.ts +++ b/src/type/validate.ts @@ -1,21 +1,44 @@ -import objectValues from "../polyfills/objectValues"; - -import inspect from "../jsutils/inspect"; - -import { GraphQLError } from "../error/GraphQLError"; -import { locatedError } from "../error/locatedError"; - -import { ASTNode, NamedTypeNode, DirectiveNode, OperationTypeNode } from "../language/ast"; - -import { isValidNameError } from "../utilities/assertValidName"; -import { isEqualType, isTypeSubTypeOf } from "../utilities/typeComparators"; - -import { GraphQLSchema } from "./schema"; -import { GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType } from "./definition"; -import { assertSchema } from "./schema"; -import { isIntrospectionType } from "./introspection"; -import { isDirective, GraphQLDeprecatedDirective } from "./directives"; -import { isObjectType, isInterfaceType, isUnionType, isEnumType, isInputObjectType, isNamedType, isNonNullType, isInputType, isOutputType, isRequiredArgument, isRequiredInputField } from "./definition"; +import objectValues from '../polyfills/objectValues'; + +import inspect from '../jsutils/inspect'; + +import { GraphQLError } from '../error/GraphQLError'; +import { locatedError } from '../error/locatedError'; + +import { + ASTNode, + NamedTypeNode, + DirectiveNode, + OperationTypeNode, +} from '../language/ast'; + +import { isValidNameError } from '../utilities/assertValidName'; +import { isEqualType, isTypeSubTypeOf } from '../utilities/typeComparators'; + +import { GraphQLSchema } from './schema'; +import { + GraphQLObjectType, + GraphQLInterfaceType, + GraphQLUnionType, + GraphQLEnumType, + GraphQLInputObjectType, +} from './definition'; +import { assertSchema } from './schema'; +import { isIntrospectionType } from './introspection'; +import { isDirective, GraphQLDeprecatedDirective } from './directives'; +import { + isObjectType, + isInterfaceType, + isUnionType, + isEnumType, + isInputObjectType, + isNamedType, + isNonNullType, + isInputType, + isOutputType, + isRequiredArgument, + isRequiredInputField, +} from './definition'; /** * Implements the "Type Validation" sub-sections of the specification's @@ -24,7 +47,9 @@ import { isObjectType, isInterfaceType, isUnionType, isEnumType, isInputObjectTy * Validation runs synchronously, returning an array of encountered errors, or * an empty array if no errors were encountered and the Schema is valid. */ -export function validateSchema(schema: GraphQLSchema): ReadonlyArray { +export function validateSchema( + schema: GraphQLSchema, +): ReadonlyArray { // First check to ensure the provided value is in fact a GraphQLSchema. assertSchema(schema); @@ -53,21 +78,25 @@ export function validateSchema(schema: GraphQLSchema): ReadonlyArray error.message).join('\n\n')); + throw new Error(errors.map((error) => error.message).join('\n\n')); } } class SchemaValidationContext { - - +_errors: Array; - +schema: GraphQLSchema; + readonly _errors: Array; + readonly schema: GraphQLSchema; constructor(schema) { this._errors = []; this.schema = schema; } - reportError(message: string, nodes?: ReadonlyArray | (ASTNode | null | undefined)): void { + reportError( + message: string, + nodes?: + | ReadonlyArray + | (ASTNode | null | undefined), + ): void { const _nodes = Array.isArray(nodes) ? nodes.filter(Boolean) : nodes; this.addError(new GraphQLError(message, _nodes)); } @@ -87,22 +116,38 @@ function validateRootTypes(context: SchemaValidationContext): void { if (!queryType) { context.reportError('Query root type must be provided.', schema.astNode); } else if (!isObjectType(queryType)) { - context.reportError(`Query root type must be Object type, it cannot be ${inspect(queryType)}.`, getOperationTypeNode(schema, 'query') ?? queryType.astNode); + context.reportError( + `Query root type must be Object type, it cannot be ${inspect( + queryType, + )}.`, + getOperationTypeNode(schema, 'query') ?? queryType.astNode, + ); } const mutationType = schema.getMutationType(); if (mutationType && !isObjectType(mutationType)) { - context.reportError('Mutation root type must be Object type if provided, it cannot be ' + `${inspect(mutationType)}.`, getOperationTypeNode(schema, 'mutation') ?? mutationType.astNode); + context.reportError( + 'Mutation root type must be Object type if provided, it cannot be ' + + `${inspect(mutationType)}.`, + getOperationTypeNode(schema, 'mutation') ?? mutationType.astNode, + ); } const subscriptionType = schema.getSubscriptionType(); if (subscriptionType && !isObjectType(subscriptionType)) { - context.reportError('Subscription root type must be Object type if provided, it cannot be ' + `${inspect(subscriptionType)}.`, getOperationTypeNode(schema, 'subscription') ?? subscriptionType.astNode); + context.reportError( + 'Subscription root type must be Object type if provided, it cannot be ' + + `${inspect(subscriptionType)}.`, + getOperationTypeNode(schema, 'subscription') ?? subscriptionType.astNode, + ); } } -function getOperationTypeNode(schema: GraphQLSchema, operation: OperationTypeNode): ASTNode | null | undefined { - const operationNodes = getAllSubNodes(schema, node => node.operationTypes); +function getOperationTypeNode( + schema: GraphQLSchema, + operation: OperationTypeNode, +): ASTNode | null | undefined { + const operationNodes = getAllSubNodes(schema, (node) => node.operationTypes); for (const node of operationNodes) { if (node.operation === operation) { return node.type; @@ -115,7 +160,10 @@ function validateDirectives(context: SchemaValidationContext): void { for (const directive of context.schema.getDirectives()) { // Ensure all directives are in fact GraphQL directives. if (!isDirective(directive)) { - context.reportError(`Expected directive but got: ${inspect(directive)}.`, (directive?.astNode)); + context.reportError( + `Expected directive but got: ${inspect(directive)}.`, + directive?.astNode, + ); continue; } @@ -131,18 +179,30 @@ function validateDirectives(context: SchemaValidationContext): void { // Ensure the type is an input type. if (!isInputType(arg.type)) { - context.reportError(`The type of @${directive.name}(${arg.name}:) must be Input Type ` + `but got: ${inspect(arg.type)}.`, arg.astNode); + context.reportError( + `The type of @${directive.name}(${arg.name}:) must be Input Type ` + + `but got: ${inspect(arg.type)}.`, + arg.astNode, + ); } if (isRequiredArgument(arg) && arg.deprecationReason != null) { - context.reportError(`Required argument @${directive.name}(${arg.name}:) cannot be deprecated.`, [getDeprecatedDirectiveNode(arg.astNode), // istanbul ignore next (TODO need to write coverage tests) - arg.astNode?.type]); + context.reportError( + `Required argument @${directive.name}(${arg.name}:) cannot be deprecated.`, + [ + getDeprecatedDirectiveNode(arg.astNode), // istanbul ignore next (TODO need to write coverage tests) + arg.astNode?.type, + ], + ); } } } } -function validateName(context: SchemaValidationContext, node: {readonly name: string;readonly astNode: ASTNode | null | undefined;}): void { +function validateName( + context: SchemaValidationContext, + node: { readonly name: string; readonly astNode: ASTNode | null | undefined }, +): void { // Ensure names are valid, however introspection types opt out. const error = isValidNameError(node.name); if (error) { @@ -151,12 +211,17 @@ function validateName(context: SchemaValidationContext, node: {readonly name: st } function validateTypes(context: SchemaValidationContext): void { - const validateInputObjectCircularRefs = createInputObjectCircularRefsValidator(context); + const validateInputObjectCircularRefs = createInputObjectCircularRefsValidator( + context, + ); const typeMap = context.schema.getTypeMap(); for (const type of objectValues(typeMap)) { // Ensure all provided types are in fact GraphQL type. if (!isNamedType(type)) { - context.reportError(`Expected GraphQL named type but got: ${inspect(type)}.`, type.astNode); + context.reportError( + `Expected GraphQL named type but got: ${inspect(type)}.`, + type.astNode, + ); continue; } @@ -193,12 +258,18 @@ function validateTypes(context: SchemaValidationContext): void { } } -function validateFields(context: SchemaValidationContext, type: GraphQLObjectType | GraphQLInterfaceType): void { +function validateFields( + context: SchemaValidationContext, + type: GraphQLObjectType | GraphQLInterfaceType, +): void { const fields = objectValues(type.getFields()); // Objects and Interfaces both must define one or more fields. if (fields.length === 0) { - context.reportError(`Type ${type.name} must define one or more fields.`, getAllNodes(type)); + context.reportError( + `Type ${type.name} must define one or more fields.`, + getAllNodes(type), + ); } for (const field of fields) { @@ -207,7 +278,11 @@ function validateFields(context: SchemaValidationContext, type: GraphQLObjectTyp // Ensure the type is an output type if (!isOutputType(field.type)) { - context.reportError(`The type of ${type.name}.${field.name} must be Output Type ` + `but got: ${inspect(field.type)}.`, (field.astNode?.type)); + context.reportError( + `The type of ${type.name}.${field.name} must be Output Type ` + + `but got: ${inspect(field.type)}.`, + field.astNode?.type, + ); } // Ensure the arguments are valid @@ -219,32 +294,54 @@ function validateFields(context: SchemaValidationContext, type: GraphQLObjectTyp // Ensure the type is an input type if (!isInputType(arg.type)) { - context.reportError(`The type of ${type.name}.${field.name}(${argName}:) must be Input ` + `Type but got: ${inspect(arg.type)}.`, (arg.astNode?.type)); + context.reportError( + `The type of ${type.name}.${field.name}(${argName}:) must be Input ` + + `Type but got: ${inspect(arg.type)}.`, + arg.astNode?.type, + ); } if (isRequiredArgument(arg) && arg.deprecationReason != null) { - context.reportError(`Required argument ${type.name}.${field.name}(${argName}:) cannot be deprecated.`, [getDeprecatedDirectiveNode(arg.astNode), // istanbul ignore next (TODO need to write coverage tests) - arg.astNode?.type]); + context.reportError( + `Required argument ${type.name}.${field.name}(${argName}:) cannot be deprecated.`, + [ + getDeprecatedDirectiveNode(arg.astNode), // istanbul ignore next (TODO need to write coverage tests) + arg.astNode?.type, + ], + ); } } } } -function validateInterfaces(context: SchemaValidationContext, type: GraphQLObjectType | GraphQLInterfaceType): void { +function validateInterfaces( + context: SchemaValidationContext, + type: GraphQLObjectType | GraphQLInterfaceType, +): void { const ifaceTypeNames = Object.create(null); for (const iface of type.getInterfaces()) { if (!isInterfaceType(iface)) { - context.reportError(`Type ${inspect(type)} must only implement Interface types, ` + `it cannot implement ${inspect(iface)}.`, getAllImplementsInterfaceNodes(type, iface)); + context.reportError( + `Type ${inspect(type)} must only implement Interface types, ` + + `it cannot implement ${inspect(iface)}.`, + getAllImplementsInterfaceNodes(type, iface), + ); continue; } if (type === iface) { - context.reportError(`Type ${type.name} cannot implement itself because it would create a circular reference.`, getAllImplementsInterfaceNodes(type, iface)); + context.reportError( + `Type ${type.name} cannot implement itself because it would create a circular reference.`, + getAllImplementsInterfaceNodes(type, iface), + ); continue; } if (ifaceTypeNames[iface.name]) { - context.reportError(`Type ${type.name} can only implement ${iface.name} once.`, getAllImplementsInterfaceNodes(type, iface)); + context.reportError( + `Type ${type.name} can only implement ${iface.name} once.`, + getAllImplementsInterfaceNodes(type, iface), + ); continue; } @@ -255,7 +352,11 @@ function validateInterfaces(context: SchemaValidationContext, type: GraphQLObjec } } -function validateTypeImplementsInterface(context: SchemaValidationContext, type: GraphQLObjectType | GraphQLInterfaceType, iface: GraphQLInterfaceType): void { +function validateTypeImplementsInterface( + context: SchemaValidationContext, + type: GraphQLObjectType | GraphQLInterfaceType, + iface: GraphQLInterfaceType, +): void { const typeFieldMap = type.getFields(); // Assert each interface field is implemented. @@ -265,26 +366,39 @@ function validateTypeImplementsInterface(context: SchemaValidationContext, type: // Assert interface field exists on type. if (!typeField) { - context.reportError(`Interface field ${iface.name}.${fieldName} expected but ${type.name} does not provide it.`, [ifaceField.astNode, ...getAllNodes(type)]); + context.reportError( + `Interface field ${iface.name}.${fieldName} expected but ${type.name} does not provide it.`, + [ifaceField.astNode, ...getAllNodes(type)], + ); continue; } // Assert interface field type is satisfied by type field type, by being // a valid subtype. (covariant) if (!isTypeSubTypeOf(context.schema, typeField.type, ifaceField.type)) { - context.reportError(`Interface field ${iface.name}.${fieldName} expects type ` + `${inspect(ifaceField.type)} but ${type.name}.${fieldName} ` + `is type ${inspect(typeField.type)}.`, [// istanbul ignore next (TODO need to write coverage tests) - ifaceField.astNode?.type, // istanbul ignore next (TODO need to write coverage tests) - typeField.astNode?.type]); + context.reportError( + `Interface field ${iface.name}.${fieldName} expects type ` + + `${inspect(ifaceField.type)} but ${type.name}.${fieldName} ` + + `is type ${inspect(typeField.type)}.`, + [ + // istanbul ignore next (TODO need to write coverage tests) + ifaceField.astNode?.type, // istanbul ignore next (TODO need to write coverage tests) + typeField.astNode?.type, + ], + ); } // Assert each interface field arg is implemented. for (const ifaceArg of ifaceField.args) { const argName = ifaceArg.name; - const typeArg = typeField.args.find(arg => arg.name === argName); + const typeArg = typeField.args.find((arg) => arg.name === argName); // Assert interface field arg exists on object field. if (!typeArg) { - context.reportError(`Interface field argument ${iface.name}.${fieldName}(${argName}:) expected but ${type.name}.${fieldName} does not provide it.`, [ifaceArg.astNode, typeField.astNode]); + context.reportError( + `Interface field argument ${iface.name}.${fieldName}(${argName}:) expected but ${type.name}.${fieldName} does not provide it.`, + [ifaceArg.astNode, typeField.astNode], + ); continue; } @@ -292,9 +406,17 @@ function validateTypeImplementsInterface(context: SchemaValidationContext, type: // (invariant) // TODO: change to contravariant? if (!isEqualType(ifaceArg.type, typeArg.type)) { - context.reportError(`Interface field argument ${iface.name}.${fieldName}(${argName}:) ` + `expects type ${inspect(ifaceArg.type)} but ` + `${type.name}.${fieldName}(${argName}:) is type ` + `${inspect(typeArg.type)}.`, [// istanbul ignore next (TODO need to write coverage tests) - ifaceArg.astNode?.type, // istanbul ignore next (TODO need to write coverage tests) - typeArg.astNode?.type]); + context.reportError( + `Interface field argument ${iface.name}.${fieldName}(${argName}:) ` + + `expects type ${inspect(ifaceArg.type)} but ` + + `${type.name}.${fieldName}(${argName}:) is type ` + + `${inspect(typeArg.type)}.`, + [ + // istanbul ignore next (TODO need to write coverage tests) + ifaceArg.astNode?.type, // istanbul ignore next (TODO need to write coverage tests) + typeArg.astNode?.type, + ], + ); } // TODO: validate default values? @@ -303,48 +425,82 @@ function validateTypeImplementsInterface(context: SchemaValidationContext, type: // Assert additional arguments must not be required. for (const typeArg of typeField.args) { const argName = typeArg.name; - const ifaceArg = ifaceField.args.find(arg => arg.name === argName); + const ifaceArg = ifaceField.args.find((arg) => arg.name === argName); if (!ifaceArg && isRequiredArgument(typeArg)) { - context.reportError(`Object field ${type.name}.${fieldName} includes required argument ${argName} that is missing from the Interface field ${iface.name}.${fieldName}.`, [typeArg.astNode, ifaceField.astNode]); + context.reportError( + `Object field ${type.name}.${fieldName} includes required argument ${argName} that is missing from the Interface field ${iface.name}.${fieldName}.`, + [typeArg.astNode, ifaceField.astNode], + ); } } } } -function validateTypeImplementsAncestors(context: SchemaValidationContext, type: GraphQLObjectType | GraphQLInterfaceType, iface: GraphQLInterfaceType): void { +function validateTypeImplementsAncestors( + context: SchemaValidationContext, + type: GraphQLObjectType | GraphQLInterfaceType, + iface: GraphQLInterfaceType, +): void { const ifaceInterfaces = type.getInterfaces(); for (const transitive of iface.getInterfaces()) { if (ifaceInterfaces.indexOf(transitive) === -1) { - context.reportError(transitive === type ? `Type ${type.name} cannot implement ${iface.name} because it would create a circular reference.` : `Type ${type.name} must implement ${transitive.name} because it is implemented by ${iface.name}.`, [...getAllImplementsInterfaceNodes(iface, transitive), ...getAllImplementsInterfaceNodes(type, iface)]); + context.reportError( + transitive === type + ? `Type ${type.name} cannot implement ${iface.name} because it would create a circular reference.` + : `Type ${type.name} must implement ${transitive.name} because it is implemented by ${iface.name}.`, + [ + ...getAllImplementsInterfaceNodes(iface, transitive), + ...getAllImplementsInterfaceNodes(type, iface), + ], + ); } } } -function validateUnionMembers(context: SchemaValidationContext, union: GraphQLUnionType): void { +function validateUnionMembers( + context: SchemaValidationContext, + union: GraphQLUnionType, +): void { const memberTypes = union.getTypes(); if (memberTypes.length === 0) { - context.reportError(`Union type ${union.name} must define one or more member types.`, getAllNodes(union)); + context.reportError( + `Union type ${union.name} must define one or more member types.`, + getAllNodes(union), + ); } const includedTypeNames = Object.create(null); for (const memberType of memberTypes) { if (includedTypeNames[memberType.name]) { - context.reportError(`Union type ${union.name} can only include type ${memberType.name} once.`, getUnionMemberTypeNodes(union, memberType.name)); + context.reportError( + `Union type ${union.name} can only include type ${memberType.name} once.`, + getUnionMemberTypeNodes(union, memberType.name), + ); continue; } includedTypeNames[memberType.name] = true; if (!isObjectType(memberType)) { - context.reportError(`Union type ${union.name} can only include Object types, ` + `it cannot include ${inspect(memberType)}.`, getUnionMemberTypeNodes(union, String(memberType))); + context.reportError( + `Union type ${union.name} can only include Object types, ` + + `it cannot include ${inspect(memberType)}.`, + getUnionMemberTypeNodes(union, String(memberType)), + ); } } } -function validateEnumValues(context: SchemaValidationContext, enumType: GraphQLEnumType): void { +function validateEnumValues( + context: SchemaValidationContext, + enumType: GraphQLEnumType, +): void { const enumValues = enumType.getValues(); if (enumValues.length === 0) { - context.reportError(`Enum type ${enumType.name} must define one or more values.`, getAllNodes(enumType)); + context.reportError( + `Enum type ${enumType.name} must define one or more values.`, + getAllNodes(enumType), + ); } for (const enumValue of enumValues) { @@ -353,16 +509,25 @@ function validateEnumValues(context: SchemaValidationContext, enumType: GraphQLE // Ensure valid name. validateName(context, enumValue); if (valueName === 'true' || valueName === 'false' || valueName === 'null') { - context.reportError(`Enum type ${enumType.name} cannot include value: ${valueName}.`, enumValue.astNode); + context.reportError( + `Enum type ${enumType.name} cannot include value: ${valueName}.`, + enumValue.astNode, + ); } } } -function validateInputFields(context: SchemaValidationContext, inputObj: GraphQLInputObjectType): void { +function validateInputFields( + context: SchemaValidationContext, + inputObj: GraphQLInputObjectType, +): void { const fields = objectValues(inputObj.getFields()); if (fields.length === 0) { - context.reportError(`Input Object type ${inputObj.name} must define one or more fields.`, getAllNodes(inputObj)); + context.reportError( + `Input Object type ${inputObj.name} must define one or more fields.`, + getAllNodes(inputObj), + ); } // Ensure the arguments are valid @@ -372,17 +537,28 @@ function validateInputFields(context: SchemaValidationContext, inputObj: GraphQL // Ensure the type is an input type if (!isInputType(field.type)) { - context.reportError(`The type of ${inputObj.name}.${field.name} must be Input Type ` + `but got: ${inspect(field.type)}.`, (field.astNode?.type)); + context.reportError( + `The type of ${inputObj.name}.${field.name} must be Input Type ` + + `but got: ${inspect(field.type)}.`, + field.astNode?.type, + ); } if (isRequiredInputField(field) && field.deprecationReason != null) { - context.reportError(`Required input field ${inputObj.name}.${field.name} cannot be deprecated.`, [getDeprecatedDirectiveNode(field.astNode), // istanbul ignore next (TODO need to write coverage tests) - field.astNode?.type]); + context.reportError( + `Required input field ${inputObj.name}.${field.name} cannot be deprecated.`, + [ + getDeprecatedDirectiveNode(field.astNode), // istanbul ignore next (TODO need to write coverage tests) + field.astNode?.type, + ], + ); } } } -function createInputObjectCircularRefsValidator(context: SchemaValidationContext): (arg0: GraphQLInputObjectType) => void { +function createInputObjectCircularRefsValidator( + context: SchemaValidationContext, +): (arg0: GraphQLInputObjectType) => void { // Modified copy of algorithm from 'src/validation/rules/NoFragmentCycles.js'. // Tracks already visited types to maintain O(N) and to ensure that cycles // are not redundantly reported. @@ -418,8 +594,11 @@ function createInputObjectCircularRefsValidator(context: SchemaValidationContext detectCycleRecursive(fieldType); } else { const cyclePath = fieldPath.slice(cycleIndex); - const pathStr = cyclePath.map(fieldObj => fieldObj.name).join('.'); - context.reportError(`Cannot reference Input Object "${fieldType.name}" within itself through a series of non-null fields: "${pathStr}".`, cyclePath.map(fieldObj => fieldObj.astNode)); + const pathStr = cyclePath.map((fieldObj) => fieldObj.name).join('.'); + context.reportError( + `Cannot reference Input Object "${fieldType.name}" within itself through a series of non-null fields: "${pathStr}".`, + cyclePath.map((fieldObj) => fieldObj.astNode), + ); } fieldPath.pop(); } @@ -432,18 +611,27 @@ function createInputObjectCircularRefsValidator(context: SchemaValidationContext type SDLDefinedObject = { readonly astNode: T | null | undefined; readonly extensionASTNodes?: ReadonlyArray | null | undefined; - }; -function getAllNodes(object: SDLDefinedObject): ReadonlyArray { - const { - astNode, - extensionASTNodes - } = object; - return astNode ? extensionASTNodes ? [astNode].concat(extensionASTNodes) : [astNode] : extensionASTNodes ?? []; +function getAllNodes( + object: SDLDefinedObject, +): ReadonlyArray { + const { astNode, extensionASTNodes } = object; + return astNode + ? extensionASTNodes + ? [astNode].concat(extensionASTNodes) + : [astNode] + : extensionASTNodes ?? []; } -function getAllSubNodes(object: SDLDefinedObject, getter: (arg0: T | K) => (L | ReadonlyArray) | null | undefined): ReadonlyArray { +function getAllSubNodes< + T extends ASTNode, + K extends ASTNode, + L extends ASTNode +>( + object: SDLDefinedObject, + getter: (arg0: T | K) => (L | ReadonlyArray) | null | undefined, +): ReadonlyArray { let subNodes = []; for (const node of getAllNodes(object)) { // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') @@ -452,15 +640,32 @@ function getAllSubNodes return subNodes; } -function getAllImplementsInterfaceNodes(type: GraphQLObjectType | GraphQLInterfaceType, iface: GraphQLInterfaceType): ReadonlyArray { - return getAllSubNodes(type, typeNode => typeNode.interfaces).filter(ifaceNode => ifaceNode.name.value === iface.name); +function getAllImplementsInterfaceNodes( + type: GraphQLObjectType | GraphQLInterfaceType, + iface: GraphQLInterfaceType, +): ReadonlyArray { + return getAllSubNodes(type, (typeNode) => typeNode.interfaces).filter( + (ifaceNode) => ifaceNode.name.value === iface.name, + ); } -function getUnionMemberTypeNodes(union: GraphQLUnionType, typeName: string): ReadonlyArray | null | undefined { - return getAllSubNodes(union, unionNode => unionNode.types).filter(typeNode => typeNode.name.value === typeName); +function getUnionMemberTypeNodes( + union: GraphQLUnionType, + typeName: string, +): ReadonlyArray | null | undefined { + return getAllSubNodes(union, (unionNode) => unionNode.types).filter( + (typeNode) => typeNode.name.value === typeName, + ); } -function getDeprecatedDirectiveNode(definitionNode: {readonly directives?: ReadonlyArray;} | null | undefined): DirectiveNode | null | undefined { +function getDeprecatedDirectiveNode( + definitionNode: + | { readonly directives?: ReadonlyArray } + | null + | undefined, +): DirectiveNode | null | undefined { // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203') - return definitionNode?.directives?.find(node => node.name.value === GraphQLDeprecatedDirective.name); -} \ No newline at end of file + return definitionNode?.directives?.find( + (node) => node.name.value === GraphQLDeprecatedDirective.name, + ); +} From 33fcb3fecbbd95dfcb7bd5eca74d0790b1e65f94 Mon Sep 17 00:00:00 2001 From: Saihajpreet Singh Date: Wed, 18 Nov 2020 09:51:15 -0600 Subject: [PATCH 3/8] build: relax tsconfig --- tsconfig.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index d25aa26463b..ecf27a4bedb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,12 +2,13 @@ "compilerOptions": { "module": "commonjs", "lib": ["es6", "esnext.asynciterable"], - "noImplicitAny": true, - "noImplicitThis": true, - "strictNullChecks": true, - "strictFunctionTypes": true, + "noImplicitAny": false, + "noImplicitThis": false, + "strictNullChecks": false, + "strictFunctionTypes": false, "types": [], "noEmit": true, "forceConsistentCasingInFileNames": true - } + }, + "exclude": ["integrationTests/*/**"] } From 026139f1a38c29c158acc8c3a33c71937196748b Mon Sep 17 00:00:00 2001 From: Saihajpreet Singh Date: Wed, 18 Nov 2020 10:04:11 -0600 Subject: [PATCH 4/8] fix: Type annotation cannot appear on a constructor declaration --- src/error/GraphQLError.ts | 2 +- src/language/source.ts | 2 +- src/type/definition.ts | 10 +++++----- src/type/directives.ts | 2 +- src/type/schema.ts | 2 +- src/utilities/TypeInfo.ts | 2 +- src/validation/ValidationContext.ts | 6 +++--- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/error/GraphQLError.ts b/src/error/GraphQLError.ts index 1cdd9ef74b5..1cf1e2dff42 100644 --- a/src/error/GraphQLError.ts +++ b/src/error/GraphQLError.ts @@ -92,7 +92,7 @@ export class GraphQLError extends Error { } | null | undefined, - ): void { + ) { super(message); // Compute list of blame nodes. diff --git a/src/language/source.ts b/src/language/source.ts index 4b4faf1e36d..e737bf7ec8c 100644 --- a/src/language/source.ts +++ b/src/language/source.ts @@ -23,7 +23,7 @@ export class Source { body: string, name: string = 'GraphQL request', locationOffset: Location = { line: 1, column: 1 }, - ): void { + ) { devAssert( typeof body === 'string', `Body must be a string. Received: ${inspect(body)}.`, diff --git a/src/type/definition.ts b/src/type/definition.ts index 2d5a093e000..c7a545260af 100644 --- a/src/type/definition.ts +++ b/src/type/definition.ts @@ -697,7 +697,7 @@ export class GraphQLObjectType { _fields: Thunk>; _interfaces: Thunk>; - constructor(config: $ReadOnly>): void { + constructor(config: $ReadOnly>) { this.name = config.name; this.description = config.description; this.isTypeOf = config.isTypeOf; @@ -1022,7 +1022,7 @@ export class GraphQLInterfaceType { _fields: Thunk>; _interfaces: Thunk>; - constructor(config: $ReadOnly>): void { + constructor(config: $ReadOnly>) { this.name = config.name; this.description = config.description; this.resolveType = config.resolveType; @@ -1139,7 +1139,7 @@ export class GraphQLUnionType { _types: Thunk>; - constructor(config: $ReadOnly>): void { + constructor(config: $ReadOnly>) { this.name = config.name; this.description = config.description; this.resolveType = config.resolveType; @@ -1265,7 +1265,7 @@ export class GraphQLEnumType { GraphQLEnumTypeConfig /* */ >, - ): void { + ) { this.name = config.name; this.description = config.description; this.extensions = config.extensions && toObjMap(config.extensions); @@ -1502,7 +1502,7 @@ export class GraphQLInputObjectType { _fields: Thunk; - constructor(config: $ReadOnly): void { + constructor(config: $ReadOnly) { this.name = config.name; this.description = config.description; this.extensions = config.extensions && toObjMap(config.extensions); diff --git a/src/type/directives.ts b/src/type/directives.ts index 1fa1d5ba1fd..2eabe531010 100644 --- a/src/type/directives.ts +++ b/src/type/directives.ts @@ -47,7 +47,7 @@ export class GraphQLDirective { extensions: ReadOnlyObjMap | null | undefined; astNode: DirectiveDefinitionNode | null | undefined; - constructor(config: $ReadOnly): void { + constructor(config: $ReadOnly) { this.name = config.name; this.description = config.description; this.locations = config.locations; diff --git a/src/type/schema.ts b/src/type/schema.ts index 93c7cae1ce6..c8a10149e72 100644 --- a/src/type/schema.ts +++ b/src/type/schema.ts @@ -132,7 +132,7 @@ export class GraphQLSchema { // Used as a cache for validateSchema(). __validationErrors: ReadonlyArray | null | undefined; - constructor(config: $ReadOnly): void { + constructor(config: $ReadOnly) { // If this schema was built from a source known to be valid, then it may be // marked with assumeValid to avoid an additional type system validation. this.__validationErrors = config.assumeValid === true ? [] : undefined; diff --git a/src/utilities/TypeInfo.ts b/src/utilities/TypeInfo.ts index 136b15b3c3d..4a31b74b9ec 100644 --- a/src/utilities/TypeInfo.ts +++ b/src/utilities/TypeInfo.ts @@ -60,7 +60,7 @@ export class TypeInfo { getFieldDefFn?: typeof getFieldDef, // Initial type may be provided in rare cases to facilitate traversals // beginning somewhere other than documents. initialType?: GraphQLType, - ): void { + ) { this._schema = schema; this._typeStack = []; this._parentTypeStack = []; diff --git a/src/validation/ValidationContext.ts b/src/validation/ValidationContext.ts index 97cf6e443f7..473ae21aba2 100644 --- a/src/validation/ValidationContext.ts +++ b/src/validation/ValidationContext.ts @@ -50,7 +50,7 @@ export class ASTValidationContext { ReadonlyArray >; - constructor(ast: DocumentNode, onError: (err: GraphQLError) => void): void { + constructor(ast: DocumentNode, onError: (err: GraphQLError) => void) { this._ast = ast; this._fragments = undefined; this._fragmentSpreads = new Map(); @@ -141,7 +141,7 @@ export class SDLValidationContext extends ASTValidationContext { ast: DocumentNode, schema: GraphQLSchema | null | undefined, onError: (err: GraphQLError) => void, - ): void { + ) { super(ast, onError); this._schema = schema; } @@ -167,7 +167,7 @@ export class ValidationContext extends ASTValidationContext { ast: DocumentNode, typeInfo: TypeInfo, onError: (err: GraphQLError) => void, - ): void { + ) { super(ast, onError); this._schema = schema; this._typeInfo = typeInfo; From dc5bbdb0cdd661537466f34809e569a388be5bae Mon Sep 17 00:00:00 2001 From: Saihajpreet Singh Date: Wed, 18 Nov 2020 10:09:17 -0600 Subject: [PATCH 5/8] build: temporarily disable TS eslint rules --- .eslintrc.yml | 142 +++++++++++++++++++++++--------------------------- 1 file changed, 64 insertions(+), 78 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index 1cc804d7b5d..bef6869a55b 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -509,84 +509,80 @@ overrides: # Supported Rules # https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#supported-rules - '@typescript-eslint/adjacent-overload-signatures': error - '@typescript-eslint/array-type': [error, { default: generic }] - '@typescript-eslint/await-thenable': error - '@typescript-eslint/ban-ts-comment': [error, { 'ts-expect-error': false }] - '@typescript-eslint/ban-tslint-comment': error - '@typescript-eslint/ban-types': error - '@typescript-eslint/class-literal-property-style': off # TODO enable after TS conversion - '@typescript-eslint/consistent-indexed-object-style': off # TODO enable after TS conversion - '@typescript-eslint/consistent-type-assertions': - [error, { assertionStyle: as, objectLiteralTypeAssertions: never }] + '@typescript-eslint/adjacent-overload-signatures': off #TODO temporarily disabled + '@typescript-eslint/array-type': off #TODO temporarily disabled + '@typescript-eslint/await-thenable': off #TODO temporarily disabled + '@typescript-eslint/ban-ts-comment': off #TODO temporarily disabled + '@typescript-eslint/ban-tslint-comment': off #TODO temporarily disabled + '@typescript-eslint/ban-types': off #TODO temporarily disabled + '@typescript-eslint/class-literal-property-style': off + '@typescript-eslint/consistent-type-assertions': off #TODO temporarily disabled '@typescript-eslint/consistent-type-definitions': off # TODO consider '@typescript-eslint/consistent-type-imports': off # TODO enable after TS conversion '@typescript-eslint/explicit-function-return-type': off # TODO consider '@typescript-eslint/explicit-member-accessibility': off # TODO consider '@typescript-eslint/explicit-module-boundary-types': off # TODO consider '@typescript-eslint/member-ordering': off # TODO consider - '@typescript-eslint/method-signature-style': error + '@typescript-eslint/method-signature-style': off #TODO temporarily disabled '@typescript-eslint/naming-convention': off # TODO consider - '@typescript-eslint/no-base-to-string': error - '@typescript-eslint/no-confusing-non-null-assertion': error + '@typescript-eslint/no-base-to-string': off #TODO temporarily disabled + '@typescript-eslint/no-confusing-non-null-assertion': off #TODO temporarily disabled '@typescript-eslint/no-dynamic-delete': off - '@typescript-eslint/no-empty-interface': error + '@typescript-eslint/no-empty-interface': off #TODO temporarily disabled '@typescript-eslint/no-explicit-any': off # TODO error - '@typescript-eslint/no-extra-non-null-assertion': error + '@typescript-eslint/no-extra-non-null-assertion': off #TODO temporarily disabled '@typescript-eslint/no-extraneous-class': off # TODO consider - '@typescript-eslint/no-floating-promises': error - '@typescript-eslint/no-for-in-array': error + '@typescript-eslint/no-floating-promises': off #TODO temporarily disabled + '@typescript-eslint/no-for-in-array': off #TODO temporarily disabled '@typescript-eslint/no-implicit-any-catch': off # TODO: Enable after TS convertion - '@typescript-eslint/no-implied-eval': error - '@typescript-eslint/no-inferrable-types': - [error, { ignoreParameters: true, ignoreProperties: true }] - '@typescript-eslint/no-misused-new': error - '@typescript-eslint/no-misused-promises': error - '@typescript-eslint/no-namespace': error - '@typescript-eslint/no-non-null-asserted-optional-chain': error - '@typescript-eslint/no-non-null-assertion': error - '@typescript-eslint/no-parameter-properties': error - '@typescript-eslint/no-invalid-void-type': error - '@typescript-eslint/no-require-imports': error - '@typescript-eslint/no-this-alias': error - '@typescript-eslint/no-throw-literal': error + '@typescript-eslint/no-implied-eval': off #TODO temporarily disabled + '@typescript-eslint/no-inferrable-types': off #TODO temporarily disabled + '@typescript-eslint/no-misused-new': off #TODO temporarily disabled + '@typescript-eslint/no-misused-promises': off #TODO temporarily disabled + '@typescript-eslint/no-namespace': off #TODO temporarily disabled + '@typescript-eslint/no-non-null-asserted-optional-chain': off #TODO temporarily disabled + '@typescript-eslint/no-non-null-assertion': off #TODO temporarily disabled + '@typescript-eslint/no-parameter-properties': off #TODO temporarily disabled + '@typescript-eslint/no-invalid-void-type': off #TODO temporarily disabled + '@typescript-eslint/no-require-imports': off #TODO temporarily disabled + '@typescript-eslint/no-this-alias': off #TODO temporarily disabled + '@typescript-eslint/no-throw-literal': off #TODO temporarily disabled '@typescript-eslint/no-type-alias': off # TODO consider - '@typescript-eslint/no-unnecessary-boolean-literal-compare': error - '@typescript-eslint/no-unnecessary-condition': error - '@typescript-eslint/no-unnecessary-qualifier': error - '@typescript-eslint/no-unnecessary-type-arguments': error - '@typescript-eslint/no-unnecessary-type-assertion': error + '@typescript-eslint/no-unnecessary-boolean-literal-compare': off #TODO temporarily disabled + '@typescript-eslint/no-unnecessary-condition': off #TODO temporarily disabled + '@typescript-eslint/no-unnecessary-qualifier': off #TODO temporarily disabled + '@typescript-eslint/no-unnecessary-type-arguments': off #TODO temporarily disabled + '@typescript-eslint/no-unnecessary-type-assertion': off #TODO temporarily disabled '@typescript-eslint/no-unsafe-assignment': off # TODO consider '@typescript-eslint/no-unsafe-call': off # TODO consider '@typescript-eslint/no-unsafe-member-access': off # TODO consider '@typescript-eslint/no-unsafe-return': off # TODO consider - '@typescript-eslint/no-var-requires': error + '@typescript-eslint/no-var-requires': off #TODO temporarily disabled '@typescript-eslint/prefer-as-const': off # TODO consider '@typescript-eslint/prefer-enum-initializers': off # TODO consider '@typescript-eslint/prefer-for-of': off # TODO switch to error after TS migration - '@typescript-eslint/prefer-function-type': error + '@typescript-eslint/prefer-function-type': off #TODO temporarily disabled '@typescript-eslint/prefer-includes': off # TODO switch to error after IE11 drop - '@typescript-eslint/prefer-literal-enum-member': error - '@typescript-eslint/prefer-namespace-keyword': error - '@typescript-eslint/prefer-nullish-coalescing': error - '@typescript-eslint/prefer-optional-chain': error - '@typescript-eslint/prefer-readonly': error + '@typescript-eslint/prefer-literal-enum-member': off #TODO temporarily disabled + '@typescript-eslint/prefer-namespace-keyword': off #TODO temporarily disabled + '@typescript-eslint/prefer-nullish-coalescing': off #TODO temporarily disabled + '@typescript-eslint/prefer-optional-chain': off #TODO temporarily disabled + '@typescript-eslint/prefer-readonly': off #TODO temporarily disabled '@typescript-eslint/prefer-readonly-parameter-types': off # TODO consider - '@typescript-eslint/prefer-reduce-type-parameter': error - '@typescript-eslint/prefer-regexp-exec': error - '@typescript-eslint/prefer-ts-expect-error': error + '@typescript-eslint/prefer-reduce-type-parameter': off #TODO temporarily disabled + '@typescript-eslint/prefer-regexp-exec': off #TODO temporarily disabled + '@typescript-eslint/prefer-ts-expect-error': off #TODO temporarily disabled '@typescript-eslint/prefer-string-starts-ends-with': off # TODO switch to error after IE11 drop '@typescript-eslint/promise-function-async': off - '@typescript-eslint/require-array-sort-compare': error - '@typescript-eslint/restrict-plus-operands': - [error, { checkCompoundAssignments: true }] - '@typescript-eslint/restrict-template-expressions': error + '@typescript-eslint/require-array-sort-compare': off #TODO temporarily disabled + '@typescript-eslint/restrict-plus-operands': off #TODO temporarily disabled + '@typescript-eslint/restrict-template-expressions': off #TODO temporarily disabled '@typescript-eslint/strict-boolean-expressions': off # TODO consider - '@typescript-eslint/switch-exhaustiveness-check': error - '@typescript-eslint/triple-slash-reference': error + '@typescript-eslint/switch-exhaustiveness-check': off #TODO temporarily disabled + '@typescript-eslint/triple-slash-reference': off #TODO temporarily disabled '@typescript-eslint/typedef': off '@typescript-eslint/unbound-method': off # TODO consider - '@typescript-eslint/unified-signatures': error + '@typescript-eslint/unified-signatures': off #TODO temporarily disabled # Extension Rules # https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#extension-rules @@ -608,32 +604,22 @@ overrides: no-useless-constructor: off require-await: off no-return-await: off - '@typescript-eslint/default-param-last': error - '@typescript-eslint/dot-notation': error - '@typescript-eslint/lines-between-class-members': - [error, always, { exceptAfterSingleLine: true }] - '@typescript-eslint/no-array-constructor': error - '@typescript-eslint/no-dupe-class-members': error - '@typescript-eslint/no-empty-function': error - '@typescript-eslint/no-invalid-this': error - '@typescript-eslint/no-loop-func': error - '@typescript-eslint/no-loss-of-precision': error - '@typescript-eslint/no-redeclare': error - '@typescript-eslint/no-shadow': error - '@typescript-eslint/no-unused-expressions': error - '@typescript-eslint/no-unused-vars': - [ - error, - { - vars: all, - args: all, - argsIgnorePattern: '^_', - varsIgnorePattern: '^_T', - }, - ] - '@typescript-eslint/no-useless-constructor': error - '@typescript-eslint/require-await': error - '@typescript-eslint/return-await': error + '@typescript-eslint/default-param-last': off #TODO temporarily disabled + '@typescript-eslint/dot-notation': off #TODO temporarily disabled + '@typescript-eslint/lines-between-class-members': off #TODO temporarily disabled + '@typescript-eslint/no-array-constructor': off #TODO temporarily disabled + '@typescript-eslint/no-dupe-class-members': off #TODO temporarily disabled + '@typescript-eslint/no-empty-function': off #TODO temporarily disabled + '@typescript-eslint/no-invalid-this': off #TODO temporarily disabled + '@typescript-eslint/no-loop-func': off #TODO temporarily disabled + '@typescript-eslint/no-loss-of-precision': off #TODO temporarily disabled + '@typescript-eslint/no-redeclare': off #TODO temporarily disabled + '@typescript-eslint/no-shadow': off #TODO temporarily disabled + '@typescript-eslint/no-unused-expressions': off #TODO temporarily disabled + '@typescript-eslint/no-unused-vars': off #TODO temporarily disabled + '@typescript-eslint/no-useless-constructor': off #TODO temporarily disabled + '@typescript-eslint/require-await': off #TODO temporarily disabled + '@typescript-eslint/return-await': off #TODO temporarily disabled # Disable for JS, Flow and TS '@typescript-eslint/init-declarations': off From 32eea6be24e5e8789e41bdcebe833cd019ae3632 Mon Sep 17 00:00:00 2001 From: Saihajpreet Singh Date: Wed, 18 Nov 2020 10:11:06 -0600 Subject: [PATCH 6/8] refactor(jsutils): TS function overloading --- src/jsutils/didYouMean.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/jsutils/didYouMean.ts b/src/jsutils/didYouMean.ts index 63bfbf823bd..c511fdee6d9 100644 --- a/src/jsutils/didYouMean.ts +++ b/src/jsutils/didYouMean.ts @@ -3,15 +3,15 @@ const MAX_SUGGESTIONS = 5; /** * Given [ A, B, C ] return ' Did you mean A, B, or C?'. */ -declare function didYouMean(suggestions: ReadonlyArray): string; -// eslint-disable-next-line no-redeclare -declare function didYouMean( +function didYouMean(suggestions: ReadonlyArray): string; +function didYouMean( subMessage: string, suggestions: ReadonlyArray, ): string; - -// eslint-disable-next-line no-redeclare -export default function didYouMean(firstArg, secondArg) { +function didYouMean( + firstArg: string | ReadonlyArray, + secondArg?: ReadonlyArray, +): string { const [subMessage, suggestionsArg] = typeof firstArg === 'string' ? [firstArg, secondArg] @@ -36,3 +36,5 @@ export default function didYouMean(firstArg, secondArg) { const lastItem = selected.pop(); return message + selected.join(', ') + ', or ' + lastItem + '?'; } + +export default didYouMean From df573bee5dbfb20b51f1f1d67c171fb91029b184 Mon Sep 17 00:00:00 2001 From: Saihajpreet Singh Date: Wed, 18 Nov 2020 10:22:00 -0600 Subject: [PATCH 7/8] build: add utility-types --- package-lock.json | 5 +++++ package.json | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index e3a749b1284..491c018953d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4972,6 +4972,11 @@ "punycode": "^2.1.0" } }, + "utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==" + }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", diff --git a/package.json b/package.json index 48cadf00f24..86b73141b77 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,9 @@ "gitpublish:npm": "bash ./resources/gitpublish.sh npm npmDist", "gitpublish:deno": "bash ./resources/gitpublish.sh deno denoDist" }, - "dependencies": {}, + "dependencies": { + "utility-types": "^3.10.0" + }, "devDependencies": { "@babel/core": "7.12.3", "@babel/plugin-transform-flow-strip-types": "7.12.1", From 02538a5efc33277254c60817954881092717156c Mon Sep 17 00:00:00 2001 From: Saihajpreet Singh Date: Wed, 18 Nov 2020 10:24:12 -0600 Subject: [PATCH 8/8] remove `<>` (flow) from unions --- src/utilities/getIntrospectionQuery.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utilities/getIntrospectionQuery.ts b/src/utilities/getIntrospectionQuery.ts index db9eb613b7f..ab683a0b61b 100644 --- a/src/utilities/getIntrospectionQuery.ts +++ b/src/utilities/getIntrospectionQuery.ts @@ -244,10 +244,10 @@ export type IntrospectionNonNullTypeRef< }; export type IntrospectionTypeRef = - | IntrospectionNamedTypeRef<> - | IntrospectionListTypeRef<> + | IntrospectionNamedTypeRef + | IntrospectionListTypeRef | IntrospectionNonNullTypeRef< - IntrospectionNamedTypeRef<> | IntrospectionListTypeRef<> + IntrospectionNamedTypeRef | IntrospectionListTypeRef >; export type IntrospectionOutputTypeRef =