From 3342e27d46bcac382f07324ea38f89956a33582f Mon Sep 17 00:00:00 2001 From: twof Date: Tue, 19 Dec 2023 21:03:53 -0800 Subject: [PATCH] Revert "[RFC] Client Controlled Nullability experiment implementation w/o execution (#3418)" This reverts commit 699ec58547c34bfeef866a2a4458615d39b16964. We're winding down work on CCN in favor of True Schema Nullability. More context: https://github.com/graphql/nullability-wg/issues/37 --- src/__testUtils__/kitchenSinkQuery.ts | 15 - src/index.ts | 5 - src/language/__tests__/lexer-test.ts | 8 - src/language/__tests__/parser-test.ts | 211 +------------- src/language/__tests__/predicates-test.ts | 9 - src/language/__tests__/printer-test.ts | 23 +- src/language/__tests__/visitor-test.ts | 270 +----------------- src/language/ast.ts | 47 +-- src/language/index.ts | 5 - src/language/kinds.ts | 5 - src/language/lexer.ts | 8 - src/language/parser.ts | 65 ----- src/language/predicates.ts | 11 - src/language/printer.ts | 32 +-- src/language/tokenKind.ts | 1 - .../__tests__/stripIgnoredCharacters-test.ts | 10 +- 16 files changed, 9 insertions(+), 716 deletions(-) diff --git a/src/__testUtils__/kitchenSinkQuery.ts b/src/__testUtils__/kitchenSinkQuery.ts index 46628b6556..9ed9a7e983 100644 --- a/src/__testUtils__/kitchenSinkQuery.ts +++ b/src/__testUtils__/kitchenSinkQuery.ts @@ -10,21 +10,6 @@ query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery { ...frag @onFragmentSpread } } - - field3! - field4? - requiredField5: field5! - requiredSelectionSet(first: 10)! @directive { - field - } - - unsetListItemsRequiredList: listField[]! - requiredListItemsUnsetList: listField[!] - requiredListItemsRequiredList: listField[!]! - unsetListItemsOptionalList: listField[]? - optionalListItemsUnsetList: listField[?] - optionalListItemsOptionalList: listField[?]? - multidimensionalList: listField[[[!]!]!]! } ... @skip(unless: $foo) { id diff --git a/src/index.ts b/src/index.ts index 27ec4301d5..e9f4c8f5a5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -233,7 +233,6 @@ export { isDefinitionNode, isExecutableDefinitionNode, isSelectionNode, - isNullabilityAssertionNode, isValueNode, isConstValueNode, isTypeNode, @@ -266,10 +265,6 @@ export type { FieldNode, ArgumentNode, FragmentArgumentNode, - NullabilityAssertionNode, - NonNullAssertionNode, - ErrorBoundaryNode, - ListNullabilityOperatorNode, ConstArgumentNode, FragmentSpreadNode, InlineFragmentNode, diff --git a/src/language/__tests__/lexer-test.ts b/src/language/__tests__/lexer-test.ts index f781e57207..85603dfaaa 100644 --- a/src/language/__tests__/lexer-test.ts +++ b/src/language/__tests__/lexer-test.ts @@ -944,13 +944,6 @@ describe('Lexer', () => { value: undefined, }); - expect(lexOne('?')).to.contain({ - kind: TokenKind.QUESTION_MARK, - start: 0, - end: 1, - value: undefined, - }); - expect(lexOne('$')).to.contain({ kind: TokenKind.DOLLAR, start: 0, @@ -1196,7 +1189,6 @@ describe('isPunctuatorTokenKind', () => { it('returns true for punctuator tokens', () => { expect(isPunctuatorToken('!')).to.equal(true); - expect(isPunctuatorToken('?')).to.equal(true); expect(isPunctuatorToken('$')).to.equal(true); expect(isPunctuatorToken('&')).to.equal(true); expect(isPunctuatorToken('(')).to.equal(true); diff --git a/src/language/__tests__/parser-test.ts b/src/language/__tests__/parser-test.ts index 215e743be7..02b5f99c13 100644 --- a/src/language/__tests__/parser-test.ts +++ b/src/language/__tests__/parser-test.ts @@ -15,10 +15,6 @@ import { parse, parseConstValue, parseType, parseValue } from '../parser.js'; import { Source } from '../source.js'; import { TokenKind } from '../tokenKind.js'; -function parseCCN(source: string) { - return parse(source, { experimentalClientControlledNullability: true }); -} - function expectSyntaxError(text: string) { return expectToThrowJSON(() => parse(text)); } @@ -173,7 +169,7 @@ describe('Parser', () => { }); it('parses kitchen sink', () => { - expect(() => parseCCN(kitchenSinkQuery)).to.not.throw(); + expect(() => parse(kitchenSinkQuery)).to.not.throw(); }); it('allows non-keywords anywhere a Name is allowed', () => { @@ -244,206 +240,6 @@ describe('Parser', () => { ).to.not.throw(); }); - it('parses required field', () => { - const result = parseCCN('{ requiredField! }'); - - expectJSON(result).toDeepNestedProperty( - 'definitions[0].selectionSet.selections[0].nullabilityAssertion', - { - kind: Kind.NON_NULL_ASSERTION, - loc: { start: 15, end: 16 }, - nullabilityAssertion: undefined, - }, - ); - }); - - it('parses optional field', () => { - expect(() => parseCCN('{ optionalField? }')).to.not.throw(); - }); - - it('does not parse field with multiple designators', () => { - expect(() => parseCCN('{ optionalField?! }')).to.throw( - 'Syntax Error: Expected Name, found "!".', - ); - - expect(() => parseCCN('{ optionalField!? }')).to.throw( - 'Syntax Error: Expected Name, found "?".', - ); - }); - - it('parses required with alias', () => { - expect(() => parseCCN('{ requiredField: field! }')).to.not.throw(); - }); - - it('parses optional with alias', () => { - expect(() => parseCCN('{ requiredField: field? }')).to.not.throw(); - }); - - it('does not parse aliased field with bang on left of colon', () => { - expect(() => parseCCN('{ requiredField!: field }')).to.throw(); - }); - - it('does not parse aliased field with question mark on left of colon', () => { - expect(() => parseCCN('{ requiredField?: field }')).to.throw(); - }); - - it('does not parse aliased field with bang on left and right of colon', () => { - expect(() => parseCCN('{ requiredField!: field! }')).to.throw(); - }); - - it('does not parse aliased field with question mark on left and right of colon', () => { - expect(() => parseCCN('{ requiredField?: field? }')).to.throw(); - }); - - it('does not parse designator on query', () => { - expect(() => parseCCN('query? { field }')).to.throw(); - }); - - it('parses required within fragment', () => { - expect(() => - parseCCN('fragment MyFragment on Query { field! }'), - ).to.not.throw(); - }); - - it('parses optional within fragment', () => { - expect(() => - parseCCN('fragment MyFragment on Query { field? }'), - ).to.not.throw(); - }); - - it('parses field with required list elements', () => { - const result = parseCCN('{ field[!] }'); - - expectJSON(result).toDeepNestedProperty( - 'definitions[0].selectionSet.selections[0].nullabilityAssertion', - { - kind: Kind.LIST_NULLABILITY_OPERATOR, - loc: { start: 7, end: 10 }, - nullabilityAssertion: { - kind: Kind.NON_NULL_ASSERTION, - loc: { start: 8, end: 9 }, - nullabilityAssertion: undefined, - }, - }, - ); - }); - - it('parses field with optional list elements', () => { - const result = parseCCN('{ field[?] }'); - - expectJSON(result).toDeepNestedProperty( - 'definitions[0].selectionSet.selections[0].nullabilityAssertion', - { - kind: Kind.LIST_NULLABILITY_OPERATOR, - loc: { start: 7, end: 10 }, - nullabilityAssertion: { - kind: Kind.ERROR_BOUNDARY, - loc: { start: 8, end: 9 }, - nullabilityAssertion: undefined, - }, - }, - ); - }); - - it('parses field with required list', () => { - const result = parseCCN('{ field[]! }'); - - expectJSON(result).toDeepNestedProperty( - 'definitions[0].selectionSet.selections[0].nullabilityAssertion', - { - kind: Kind.NON_NULL_ASSERTION, - loc: { start: 7, end: 10 }, - nullabilityAssertion: { - kind: Kind.LIST_NULLABILITY_OPERATOR, - loc: { start: 7, end: 9 }, - nullabilityAssertion: undefined, - }, - }, - ); - }); - - it('parses field with optional list', () => { - const result = parseCCN('{ field[]? }'); - - expectJSON(result).toDeepNestedProperty( - 'definitions[0].selectionSet.selections[0].nullabilityAssertion', - { - kind: Kind.ERROR_BOUNDARY, - loc: { start: 7, end: 10 }, - nullabilityAssertion: { - kind: Kind.LIST_NULLABILITY_OPERATOR, - loc: { start: 7, end: 9 }, - nullabilityAssertion: undefined, - }, - }, - ); - }); - - it('parses multidimensional field with mixed list elements', () => { - const result = parseCCN('{ field[[[?]!]]! }'); - - expectJSON(result).toDeepNestedProperty( - 'definitions[0].selectionSet.selections[0].nullabilityAssertion', - { - kind: Kind.NON_NULL_ASSERTION, - loc: { start: 7, end: 16 }, - nullabilityAssertion: { - kind: Kind.LIST_NULLABILITY_OPERATOR, - loc: { start: 7, end: 15 }, - nullabilityAssertion: { - kind: Kind.LIST_NULLABILITY_OPERATOR, - loc: { start: 8, end: 14 }, - nullabilityAssertion: { - kind: Kind.NON_NULL_ASSERTION, - loc: { start: 9, end: 13 }, - nullabilityAssertion: { - kind: Kind.LIST_NULLABILITY_OPERATOR, - loc: { start: 9, end: 12 }, - nullabilityAssertion: { - kind: Kind.ERROR_BOUNDARY, - loc: { start: 10, end: 11 }, - nullabilityAssertion: undefined, - }, - }, - }, - }, - }, - }, - ); - }); - - it('does not parse field with unbalanced brackets', () => { - expect(() => parseCCN('{ field[[] }')).to.throw( - 'Syntax Error: Expected "]", found "}".', - ); - - expect(() => parseCCN('{ field[]] }')).to.throw( - 'Syntax Error: Expected Name, found "]".', - ); - - expect(() => parse('{ field] }')).to.throw( - 'Syntax Error: Expected Name, found "]".', - ); - - expect(() => parseCCN('{ field[ }')).to.throw( - 'Syntax Error: Expected "]", found "}".', - ); - }); - - it('does not parse field with assorted invalid nullability designators', () => { - expect(() => parseCCN('{ field[][] }')).to.throw( - 'Syntax Error: Expected Name, found "[".', - ); - - expect(() => parseCCN('{ field[!!] }')).to.throw( - 'Syntax Error: Expected "]", found "!".', - ); - - expect(() => parseCCN('{ field[]?! }')).to.throw( - 'Syntax Error: Expected Name, found "!".', - ); - }); - it('creates ast', () => { const result = parse(dedent` { @@ -494,7 +290,6 @@ describe('Parser', () => { loc: { start: 9, end: 14 }, }, ], - nullabilityAssertion: undefined, directives: [], selectionSet: { kind: Kind.SELECTION_SET, @@ -510,7 +305,6 @@ describe('Parser', () => { value: 'id', }, arguments: [], - nullabilityAssertion: undefined, directives: [], selectionSet: undefined, }, @@ -524,7 +318,6 @@ describe('Parser', () => { value: 'name', }, arguments: [], - nullabilityAssertion: undefined, directives: [], selectionSet: undefined, }, @@ -572,7 +365,6 @@ describe('Parser', () => { value: 'node', }, arguments: [], - nullabilityAssertion: undefined, directives: [], selectionSet: { kind: Kind.SELECTION_SET, @@ -588,7 +380,6 @@ describe('Parser', () => { value: 'id', }, arguments: [], - nullabilityAssertion: undefined, directives: [], selectionSet: undefined, }, diff --git a/src/language/__tests__/predicates-test.ts b/src/language/__tests__/predicates-test.ts index 55e5782648..350e3f1a6b 100644 --- a/src/language/__tests__/predicates-test.ts +++ b/src/language/__tests__/predicates-test.ts @@ -8,7 +8,6 @@ import { isConstValueNode, isDefinitionNode, isExecutableDefinitionNode, - isNullabilityAssertionNode, isSelectionNode, isTypeDefinitionNode, isTypeExtensionNode, @@ -63,14 +62,6 @@ describe('AST node predicates', () => { ]); }); - it('isNullabilityAssertionNode', () => { - expect(filterNodes(isNullabilityAssertionNode)).to.deep.equal([ - 'ListNullabilityOperator', - 'NonNullAssertion', - 'ErrorBoundary', - ]); - }); - it('isValueNode', () => { expect(filterNodes(isValueNode)).to.deep.equal([ 'Variable', diff --git a/src/language/__tests__/printer-test.ts b/src/language/__tests__/printer-test.ts index 8669b64ec7..624dc75ca2 100644 --- a/src/language/__tests__/printer-test.ts +++ b/src/language/__tests__/printer-test.ts @@ -225,17 +225,11 @@ describe('Printer: Query document', () => { }); it('prints kitchen sink without altering ast', () => { - const ast = parse(kitchenSinkQuery, { - noLocation: true, - experimentalClientControlledNullability: true, - }); + const ast = parse(kitchenSinkQuery, { noLocation: true }); const astBeforePrintCall = JSON.stringify(ast); const printed = print(ast); - const printedAST = parse(printed, { - noLocation: true, - experimentalClientControlledNullability: true, - }); + const printedAST = parse(printed, { noLocation: true }); expect(printedAST).to.deep.equal(ast); expect(JSON.stringify(ast)).to.equal(astBeforePrintCall); @@ -253,19 +247,6 @@ describe('Printer: Query document', () => { ...frag @onFragmentSpread } } - field3! - field4? - requiredField5: field5! - requiredSelectionSet(first: 10)! @directive { - field - } - unsetListItemsRequiredList: listField[]! - requiredListItemsUnsetList: listField[!] - requiredListItemsRequiredList: listField[!]! - unsetListItemsOptionalList: listField[]? - optionalListItemsUnsetList: listField[?] - optionalListItemsOptionalList: listField[?]? - multidimensionalList: listField[[[!]!]!]! } ... @skip(unless: $foo) { id diff --git a/src/language/__tests__/visitor-test.ts b/src/language/__tests__/visitor-test.ts index 73b46d6830..6aceec88b6 100644 --- a/src/language/__tests__/visitor-test.ts +++ b/src/language/__tests__/visitor-test.ts @@ -550,9 +550,7 @@ describe('Visitor', () => { }); it('properly visits the kitchen sink query', () => { - const ast = parse(kitchenSinkQuery, { - experimentalClientControlledNullability: true, - }); + const ast = parse(kitchenSinkQuery); const visited: Array = []; const argsStack: Array = []; @@ -700,272 +698,6 @@ describe('Visitor', () => { ['leave', 'Field', 1, undefined], ['leave', 'SelectionSet', 'selectionSet', 'Field'], ['leave', 'Field', 0, undefined], - ['enter', 'Field', 1, undefined], - ['enter', 'Name', 'name', 'Field'], - ['leave', 'Name', 'name', 'Field'], - ['enter', 'NonNullAssertion', 'nullabilityAssertion', 'Field'], - ['leave', 'NonNullAssertion', 'nullabilityAssertion', 'Field'], - ['leave', 'Field', 1, undefined], - ['enter', 'Field', 2, undefined], - ['enter', 'Name', 'name', 'Field'], - ['leave', 'Name', 'name', 'Field'], - ['enter', 'ErrorBoundary', 'nullabilityAssertion', 'Field'], - ['leave', 'ErrorBoundary', 'nullabilityAssertion', 'Field'], - ['leave', 'Field', 2, undefined], - ['enter', 'Field', 3, undefined], - ['enter', 'Name', 'alias', 'Field'], - ['leave', 'Name', 'alias', 'Field'], - ['enter', 'Name', 'name', 'Field'], - ['leave', 'Name', 'name', 'Field'], - ['enter', 'NonNullAssertion', 'nullabilityAssertion', 'Field'], - ['leave', 'NonNullAssertion', 'nullabilityAssertion', 'Field'], - ['leave', 'Field', 3, undefined], - ['enter', 'Field', 4, undefined], - ['enter', 'Name', 'name', 'Field'], - ['leave', 'Name', 'name', 'Field'], - ['enter', 'Argument', 0, undefined], - ['enter', 'Name', 'name', 'Argument'], - ['leave', 'Name', 'name', 'Argument'], - ['enter', 'IntValue', 'value', 'Argument'], - ['leave', 'IntValue', 'value', 'Argument'], - ['leave', 'Argument', 0, undefined], - ['enter', 'Directive', 0, undefined], - ['enter', 'Name', 'name', 'Directive'], - ['leave', 'Name', 'name', 'Directive'], - ['leave', 'Directive', 0, undefined], - ['enter', 'SelectionSet', 'selectionSet', 'Field'], - ['enter', 'Field', 0, undefined], - ['enter', 'Name', 'name', 'Field'], - ['leave', 'Name', 'name', 'Field'], - ['leave', 'Field', 0, undefined], - ['leave', 'SelectionSet', 'selectionSet', 'Field'], - ['enter', 'NonNullAssertion', 'nullabilityAssertion', 'Field'], - ['leave', 'NonNullAssertion', 'nullabilityAssertion', 'Field'], - ['leave', 'Field', 4, undefined], - ['enter', 'Field', 5, undefined], - ['enter', 'Name', 'alias', 'Field'], - ['leave', 'Name', 'alias', 'Field'], - ['enter', 'Name', 'name', 'Field'], - ['leave', 'Name', 'name', 'Field'], - ['enter', 'NonNullAssertion', 'nullabilityAssertion', 'Field'], - [ - 'enter', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'NonNullAssertion', - ], - [ - 'leave', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'NonNullAssertion', - ], - ['leave', 'NonNullAssertion', 'nullabilityAssertion', 'Field'], - ['leave', 'Field', 5, undefined], - ['enter', 'Field', 6, undefined], - ['enter', 'Name', 'alias', 'Field'], - ['leave', 'Name', 'alias', 'Field'], - ['enter', 'Name', 'name', 'Field'], - ['leave', 'Name', 'name', 'Field'], - ['enter', 'ListNullabilityOperator', 'nullabilityAssertion', 'Field'], - [ - 'enter', - 'NonNullAssertion', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - [ - 'leave', - 'NonNullAssertion', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - ['leave', 'ListNullabilityOperator', 'nullabilityAssertion', 'Field'], - ['leave', 'Field', 6, undefined], - ['enter', 'Field', 7, undefined], - ['enter', 'Name', 'alias', 'Field'], - ['leave', 'Name', 'alias', 'Field'], - ['enter', 'Name', 'name', 'Field'], - ['leave', 'Name', 'name', 'Field'], - ['enter', 'NonNullAssertion', 'nullabilityAssertion', 'Field'], - [ - 'enter', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'NonNullAssertion', - ], - [ - 'enter', - 'NonNullAssertion', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - [ - 'leave', - 'NonNullAssertion', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - [ - 'leave', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'NonNullAssertion', - ], - ['leave', 'NonNullAssertion', 'nullabilityAssertion', 'Field'], - ['leave', 'Field', 7, undefined], - ['enter', 'Field', 8, undefined], - ['enter', 'Name', 'alias', 'Field'], - ['leave', 'Name', 'alias', 'Field'], - ['enter', 'Name', 'name', 'Field'], - ['leave', 'Name', 'name', 'Field'], - ['enter', 'ErrorBoundary', 'nullabilityAssertion', 'Field'], - [ - 'enter', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'ErrorBoundary', - ], - [ - 'leave', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'ErrorBoundary', - ], - ['leave', 'ErrorBoundary', 'nullabilityAssertion', 'Field'], - ['leave', 'Field', 8, undefined], - ['enter', 'Field', 9, undefined], - ['enter', 'Name', 'alias', 'Field'], - ['leave', 'Name', 'alias', 'Field'], - ['enter', 'Name', 'name', 'Field'], - ['leave', 'Name', 'name', 'Field'], - ['enter', 'ListNullabilityOperator', 'nullabilityAssertion', 'Field'], - [ - 'enter', - 'ErrorBoundary', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - [ - 'leave', - 'ErrorBoundary', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - ['leave', 'ListNullabilityOperator', 'nullabilityAssertion', 'Field'], - ['leave', 'Field', 9, undefined], - ['enter', 'Field', 10, undefined], - ['enter', 'Name', 'alias', 'Field'], - ['leave', 'Name', 'alias', 'Field'], - ['enter', 'Name', 'name', 'Field'], - ['leave', 'Name', 'name', 'Field'], - ['enter', 'ErrorBoundary', 'nullabilityAssertion', 'Field'], - [ - 'enter', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'ErrorBoundary', - ], - [ - 'enter', - 'ErrorBoundary', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - [ - 'leave', - 'ErrorBoundary', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - [ - 'leave', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'ErrorBoundary', - ], - ['leave', 'ErrorBoundary', 'nullabilityAssertion', 'Field'], - ['leave', 'Field', 10, undefined], - ['enter', 'Field', 11, undefined], - ['enter', 'Name', 'alias', 'Field'], - ['leave', 'Name', 'alias', 'Field'], - ['enter', 'Name', 'name', 'Field'], - ['leave', 'Name', 'name', 'Field'], - ['enter', 'NonNullAssertion', 'nullabilityAssertion', 'Field'], - [ - 'enter', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'NonNullAssertion', - ], - [ - 'enter', - 'NonNullAssertion', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - [ - 'enter', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'NonNullAssertion', - ], - [ - 'enter', - 'NonNullAssertion', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - [ - 'enter', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'NonNullAssertion', - ], - [ - 'enter', - 'NonNullAssertion', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - [ - 'leave', - 'NonNullAssertion', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - [ - 'leave', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'NonNullAssertion', - ], - [ - 'leave', - 'NonNullAssertion', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - [ - 'leave', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'NonNullAssertion', - ], - [ - 'leave', - 'NonNullAssertion', - 'nullabilityAssertion', - 'ListNullabilityOperator', - ], - [ - 'leave', - 'ListNullabilityOperator', - 'nullabilityAssertion', - 'NonNullAssertion', - ], - ['leave', 'NonNullAssertion', 'nullabilityAssertion', 'Field'], - ['leave', 'Field', 11, undefined], ['leave', 'SelectionSet', 'selectionSet', 'InlineFragment'], ['leave', 'InlineFragment', 1, undefined], ['enter', 'InlineFragment', 2, undefined], diff --git a/src/language/ast.ts b/src/language/ast.ts index 6b5e948864..e7ea84fd79 100644 --- a/src/language/ast.ts +++ b/src/language/ast.ts @@ -181,10 +181,7 @@ export type ASTNode = | InterfaceTypeExtensionNode | UnionTypeExtensionNode | EnumTypeExtensionNode - | InputObjectTypeExtensionNode - | NonNullAssertionNode - | ErrorBoundaryNode - | ListNullabilityOperatorNode; + | InputObjectTypeExtensionNode; /** * Utility type listing all nodes indexed by their kind. @@ -211,23 +208,9 @@ export const QueryDocumentKeys: { VariableDefinition: ['variable', 'type', 'defaultValue', 'directives'], Variable: ['name'], SelectionSet: ['selections'], - Field: [ - 'alias', - 'name', - 'arguments', - 'directives', - 'selectionSet', - // Note: Client Controlled Nullability is experimental and may be changed - // or removed in the future. - 'nullabilityAssertion', - ], + Field: ['alias', 'name', 'arguments', 'directives', 'selectionSet'], Argument: ['name', 'value'], FragmentArgument: ['name', 'value'], - // Note: Client Controlled Nullability is experimental and may be changed - // or removed in the future. - ListNullabilityOperator: ['nullabilityAssertion'], - NonNullAssertion: ['nullabilityAssertion'], - ErrorBoundary: ['nullabilityAssertion'], FragmentSpread: [ 'name', @@ -388,36 +371,10 @@ export interface FieldNode { readonly alias?: NameNode | undefined; readonly name: NameNode; readonly arguments?: ReadonlyArray | undefined; - // Note: Client Controlled Nullability is experimental - // and may be changed or removed in the future. - readonly nullabilityAssertion?: NullabilityAssertionNode | undefined; readonly directives?: ReadonlyArray | undefined; readonly selectionSet?: SelectionSetNode | undefined; } -export type NullabilityAssertionNode = - | NonNullAssertionNode - | ErrorBoundaryNode - | ListNullabilityOperatorNode; - -export interface ListNullabilityOperatorNode { - readonly kind: Kind.LIST_NULLABILITY_OPERATOR; - readonly loc?: Location | undefined; - readonly nullabilityAssertion?: NullabilityAssertionNode | undefined; -} - -export interface NonNullAssertionNode { - readonly kind: Kind.NON_NULL_ASSERTION; - readonly loc?: Location | undefined; - readonly nullabilityAssertion?: ListNullabilityOperatorNode | undefined; -} - -export interface ErrorBoundaryNode { - readonly kind: Kind.ERROR_BOUNDARY; - readonly loc?: Location | undefined; - readonly nullabilityAssertion?: ListNullabilityOperatorNode | undefined; -} - export interface ArgumentNode { readonly kind: Kind.ARGUMENT; readonly loc?: Location | undefined; diff --git a/src/language/index.ts b/src/language/index.ts index 2899f47c64..4d96766abc 100644 --- a/src/language/index.ts +++ b/src/language/index.ts @@ -39,10 +39,6 @@ export type { SelectionSetNode, SelectionNode, FieldNode, - NullabilityAssertionNode, - NonNullAssertionNode, - ErrorBoundaryNode, - ListNullabilityOperatorNode, ArgumentNode, FragmentArgumentNode /* for experimental fragment arguments */, ConstArgumentNode, @@ -98,7 +94,6 @@ export { isDefinitionNode, isExecutableDefinitionNode, isSelectionNode, - isNullabilityAssertionNode, isValueNode, isConstValueNode, isTypeNode, diff --git a/src/language/kinds.ts b/src/language/kinds.ts index edf55ac26e..52aa7c167a 100644 --- a/src/language/kinds.ts +++ b/src/language/kinds.ts @@ -14,11 +14,6 @@ enum Kind { ARGUMENT = 'Argument', FRAGMENT_ARGUMENT = 'FragmentArgument', - /** Nullability Modifiers */ - LIST_NULLABILITY_OPERATOR = 'ListNullabilityOperator', - NON_NULL_ASSERTION = 'NonNullAssertion', - ERROR_BOUNDARY = 'ErrorBoundary', - /** Fragments */ FRAGMENT_SPREAD = 'FragmentSpread', INLINE_FRAGMENT = 'InlineFragment', diff --git a/src/language/lexer.ts b/src/language/lexer.ts index cbcbf65644..300aeebbdf 100644 --- a/src/language/lexer.ts +++ b/src/language/lexer.ts @@ -91,7 +91,6 @@ export class Lexer { export function isPunctuatorTokenKind(kind: TokenKind): boolean { return ( kind === TokenKind.BANG || - kind === TokenKind.QUESTION_MARK || kind === TokenKind.DOLLAR || kind === TokenKind.AMP || kind === TokenKind.PAREN_L || @@ -299,13 +298,6 @@ function readNextToken(lexer: Lexer, start: number): Token { return createToken(lexer, TokenKind.PIPE, position, position + 1); case 0x007d: // } return createToken(lexer, TokenKind.BRACE_R, position, position + 1); - case 0x003f: // ? - return createToken( - lexer, - TokenKind.QUESTION_MARK, - position, - position + 1, - ); // StringValue case 0x0022: // " if ( diff --git a/src/language/parser.ts b/src/language/parser.ts index 30102d2fb6..521d55a1fc 100644 --- a/src/language/parser.ts +++ b/src/language/parser.ts @@ -20,7 +20,6 @@ import type { EnumTypeExtensionNode, EnumValueDefinitionNode, EnumValueNode, - ErrorBoundaryNode, FieldDefinitionNode, FieldNode, FloatValueNode, @@ -34,14 +33,11 @@ import type { InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode, IntValueNode, - ListNullabilityOperatorNode, ListTypeNode, ListValueNode, NamedTypeNode, NameNode, - NonNullAssertionNode, NonNullTypeNode, - NullabilityAssertionNode, NullValueNode, ObjectFieldNode, ObjectTypeDefinitionNode, @@ -112,29 +108,6 @@ export interface ParseOptions { * ``` */ experimentalFragmentArguments?: boolean | undefined; - - /** - * EXPERIMENTAL: - * - * If enabled, the parser will understand and parse Client Controlled Nullability - * Designators contained in Fields. They'll be represented in the - * `nullabilityAssertion` field of the FieldNode. - * - * The syntax looks like the following: - * - * ```graphql - * { - * nullableField! - * nonNullableField? - * nonNullableSelectionSet? { - * childField! - * } - * } - * ``` - * Note: this feature is experimental and may change or be removed in the - * future. - */ - experimentalClientControlledNullability?: boolean | undefined; } /** @@ -472,9 +445,6 @@ export class Parser { alias, name, arguments: this.parseArguments(false), - // Experimental support for Client Controlled Nullability changes - // the grammar of Field: - nullabilityAssertion: this.parseNullabilityAssertion(), directives: this.parseDirectives(false), selectionSet: this.peek(TokenKind.BRACE_L) ? this.parseSelectionSet() @@ -482,41 +452,6 @@ export class Parser { }); } - // TODO: add grammar comment after it finalizes - parseNullabilityAssertion(): NullabilityAssertionNode | undefined { - // Note: Client Controlled Nullability is experimental and may be changed or - // removed in the future. - if (this._options.experimentalClientControlledNullability !== true) { - return undefined; - } - - const start = this._lexer.token; - let nullabilityAssertion; - - if (this.expectOptionalToken(TokenKind.BRACKET_L)) { - const innerModifier = this.parseNullabilityAssertion(); - this.expectToken(TokenKind.BRACKET_R); - nullabilityAssertion = this.node(start, { - kind: Kind.LIST_NULLABILITY_OPERATOR, - nullabilityAssertion: innerModifier, - }); - } - - if (this.expectOptionalToken(TokenKind.BANG)) { - nullabilityAssertion = this.node(start, { - kind: Kind.NON_NULL_ASSERTION, - nullabilityAssertion, - }); - } else if (this.expectOptionalToken(TokenKind.QUESTION_MARK)) { - nullabilityAssertion = this.node(start, { - kind: Kind.ERROR_BOUNDARY, - nullabilityAssertion, - }); - } - - return nullabilityAssertion; - } - /** * Arguments[Const] : ( Argument[?Const]+ ) */ diff --git a/src/language/predicates.ts b/src/language/predicates.ts index db30b68743..29ad5bf289 100644 --- a/src/language/predicates.ts +++ b/src/language/predicates.ts @@ -3,7 +3,6 @@ import type { ConstValueNode, DefinitionNode, ExecutableDefinitionNode, - NullabilityAssertionNode, SelectionNode, TypeDefinitionNode, TypeExtensionNode, @@ -39,16 +38,6 @@ export function isSelectionNode(node: ASTNode): node is SelectionNode { ); } -export function isNullabilityAssertionNode( - node: ASTNode, -): node is NullabilityAssertionNode { - return ( - node.kind === Kind.LIST_NULLABILITY_OPERATOR || - node.kind === Kind.NON_NULL_ASSERTION || - node.kind === Kind.ERROR_BOUNDARY - ); -} - export function isValueNode(node: ASTNode): node is ValueNode { return ( node.kind === Kind.VARIABLE || diff --git a/src/language/printer.ts b/src/language/printer.ts index 9889e41bd8..c28581882e 100644 --- a/src/language/printer.ts +++ b/src/language/printer.ts @@ -55,21 +55,11 @@ const printDocASTReducer: ASTReducer = { SelectionSet: { leave: ({ selections }) => block(selections) }, Field: { - leave({ - alias, - name, - arguments: args, - nullabilityAssertion, - directives, - selectionSet, - }) { + leave({ alias, name, arguments: args, directives, selectionSet }) { const prefix = join([wrap('', alias, ': '), name], ''); return join([ wrappedLineAndArgs(prefix, args), - // Note: Client Controlled Nullability is experimental and may be - // changed or removed in the future. - nullabilityAssertion, wrap(' ', join(directives, ' ')), wrap(' ', selectionSet), ]); @@ -78,26 +68,6 @@ const printDocASTReducer: ASTReducer = { Argument: { leave: ({ name, value }) => name + ': ' + value }, FragmentArgument: { leave: ({ name, value }) => name + ': ' + value }, - // Nullability Modifiers - - ListNullabilityOperator: { - leave({ nullabilityAssertion }) { - return join(['[', nullabilityAssertion, ']']); - }, - }, - - NonNullAssertion: { - leave({ nullabilityAssertion }) { - return join([nullabilityAssertion, '!']); - }, - }, - - ErrorBoundary: { - leave({ nullabilityAssertion }) { - return join([nullabilityAssertion, '?']); - }, - }, - // Fragments FragmentSpread: { diff --git a/src/language/tokenKind.ts b/src/language/tokenKind.ts index 15c6a37aa0..37f307aba6 100644 --- a/src/language/tokenKind.ts +++ b/src/language/tokenKind.ts @@ -6,7 +6,6 @@ enum TokenKind { SOF = '', EOF = '', BANG = '!', - QUESTION_MARK = '?', DOLLAR = '$', AMP = '&', PAREN_L = '(', diff --git a/src/utilities/__tests__/stripIgnoredCharacters-test.ts b/src/utilities/__tests__/stripIgnoredCharacters-test.ts index 509f76ee3c..f334810582 100644 --- a/src/utilities/__tests__/stripIgnoredCharacters-test.ts +++ b/src/utilities/__tests__/stripIgnoredCharacters-test.ts @@ -208,14 +208,8 @@ describe('stripIgnoredCharacters', () => { const strippedQuery = stripIgnoredCharacters(kitchenSinkQuery); expect(stripIgnoredCharacters(strippedQuery)).to.equal(strippedQuery); - const queryAST = parse(kitchenSinkQuery, { - noLocation: true, - experimentalClientControlledNullability: true, - }); - const strippedAST = parse(strippedQuery, { - noLocation: true, - experimentalClientControlledNullability: true, - }); + const queryAST = parse(kitchenSinkQuery, { noLocation: true }); + const strippedAST = parse(strippedQuery, { noLocation: true }); expect(strippedAST).to.deep.equal(queryAST); });