diff options
Diffstat (limited to 'school/node_modules/graphql/language/parser.js.flow')
-rw-r--r-- | school/node_modules/graphql/language/parser.js.flow | 1568 |
1 files changed, 0 insertions, 1568 deletions
diff --git a/school/node_modules/graphql/language/parser.js.flow b/school/node_modules/graphql/language/parser.js.flow deleted file mode 100644 index ee8bd3e..0000000 --- a/school/node_modules/graphql/language/parser.js.flow +++ /dev/null @@ -1,1568 +0,0 @@ -// @flow strict -import type { GraphQLError } from '../error/GraphQLError'; -import { syntaxError } from '../error/syntaxError'; - -import type { TokenKindEnum } from './tokenKind'; -import type { - Token, - NameNode, - VariableNode, - DocumentNode, - DefinitionNode, - OperationDefinitionNode, - OperationTypeNode, - VariableDefinitionNode, - SelectionSetNode, - SelectionNode, - FieldNode, - ArgumentNode, - FragmentSpreadNode, - InlineFragmentNode, - FragmentDefinitionNode, - ValueNode, - StringValueNode, - ListValueNode, - ObjectValueNode, - ObjectFieldNode, - DirectiveNode, - TypeNode, - NamedTypeNode, - TypeSystemDefinitionNode, - SchemaDefinitionNode, - OperationTypeDefinitionNode, - ScalarTypeDefinitionNode, - ObjectTypeDefinitionNode, - FieldDefinitionNode, - InputValueDefinitionNode, - InterfaceTypeDefinitionNode, - UnionTypeDefinitionNode, - EnumTypeDefinitionNode, - EnumValueDefinitionNode, - InputObjectTypeDefinitionNode, - DirectiveDefinitionNode, - TypeSystemExtensionNode, - SchemaExtensionNode, - ScalarTypeExtensionNode, - ObjectTypeExtensionNode, - InterfaceTypeExtensionNode, - UnionTypeExtensionNode, - EnumTypeExtensionNode, - InputObjectTypeExtensionNode, -} from './ast'; -import { Kind } from './kinds'; -import { Location } from './ast'; -import { TokenKind } from './tokenKind'; -import { Source, isSource } from './source'; -import { DirectiveLocation } from './directiveLocation'; -import { Lexer, isPunctuatorTokenKind } from './lexer'; - -/** - * Configuration options to control parser behavior - */ -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, - - /** - * If enabled, the parser will parse empty fields sets in the Schema - * Definition Language. Otherwise, the parser will follow the current - * specification. - * - * This option is provided to ease adoption of the final SDL specification - * and will be removed in v16. - */ - allowLegacySDLEmptyFields?: boolean, - - /** - * If enabled, the parser will parse implemented interfaces with no `&` - * character between each interface. Otherwise, the parser will follow the - * current specification. - * - * This option is provided to ease adoption of the final SDL specification - * and will be removed in v16. - */ - allowLegacySDLImplementsInterfaces?: boolean, - - /** - * EXPERIMENTAL: - * - * If enabled, the parser will understand and parse variable definitions - * contained in a fragment definition. They'll be represented in the - * `variableDefinitions` field of the FragmentDefinitionNode. - * - * The syntax is identical to normal, query-defined variables. For example: - * - * fragment A($var: Boolean = false) on T { - * ... - * } - * - * Note: this feature is experimental and may change or be removed in the - * future. - */ - experimentalFragmentVariables?: boolean, -|}; - -/** - * Given a GraphQL source, parses it into a Document. - * Throws GraphQLError if a syntax error is encountered. - */ -export function parse( - source: string | Source, - options?: ParseOptions, -): DocumentNode { - const parser = new Parser(source, options); - return parser.parseDocument(); -} - -/** - * Given a string containing a GraphQL value (ex. `[42]`), parse the AST for - * that value. - * Throws GraphQLError if a syntax error is encountered. - * - * This is useful within tools that operate upon GraphQL Values directly and - * in isolation of complete GraphQL documents. - * - * Consider providing the results to the utility function: valueFromAST(). - */ -export function parseValue( - source: string | Source, - options?: ParseOptions, -): ValueNode { - const parser = new Parser(source, options); - parser.expectToken(TokenKind.SOF); - const value = parser.parseValueLiteral(false); - parser.expectToken(TokenKind.EOF); - return value; -} - -/** - * Given a string containing a GraphQL Type (ex. `[Int!]`), parse the AST for - * that type. - * Throws GraphQLError if a syntax error is encountered. - * - * This is useful within tools that operate upon GraphQL Types directly and - * in isolation of complete GraphQL documents. - * - * Consider providing the results to the utility function: typeFromAST(). - */ -export function parseType( - source: string | Source, - options?: ParseOptions, -): TypeNode { - const parser = new Parser(source, options); - parser.expectToken(TokenKind.SOF); - const type = parser.parseTypeReference(); - parser.expectToken(TokenKind.EOF); - return type; -} - -/** - * This class is exported only to assist people in implementing their own parsers - * without duplicating too much code and should be used only as last resort for cases - * such as experimental syntax or if certain features could not be contributed upstream. - * - * It is still part of the internal API and is versioned, so any changes to it are never - * considered breaking changes. If you still need to support multiple versions of the - * library, please use the `versionInfo` variable for version detection. - * - * @internal - */ -export class Parser { - _options: ?ParseOptions; - _lexer: Lexer; - - constructor(source: string | Source, options?: ParseOptions) { - const sourceObj = isSource(source) ? source : new Source(source); - - this._lexer = new Lexer(sourceObj); - this._options = options; - } - - /** - * Converts a name lex token into a name parse node. - */ - parseName(): NameNode { - const token = this.expectToken(TokenKind.NAME); - return { - kind: Kind.NAME, - value: ((token.value: any): string), - loc: this.loc(token), - }; - } - - // Implements the parsing rules in the Document section. - - /** - * Document : Definition+ - */ - parseDocument(): DocumentNode { - const start = this._lexer.token; - return { - kind: Kind.DOCUMENT, - definitions: this.many( - TokenKind.SOF, - this.parseDefinition, - TokenKind.EOF, - ), - loc: this.loc(start), - }; - } - - /** - * Definition : - * - ExecutableDefinition - * - TypeSystemDefinition - * - TypeSystemExtension - * - * ExecutableDefinition : - * - OperationDefinition - * - FragmentDefinition - */ - parseDefinition(): DefinitionNode { - if (this.peek(TokenKind.NAME)) { - switch (this._lexer.token.value) { - case 'query': - case 'mutation': - case 'subscription': - return this.parseOperationDefinition(); - case 'fragment': - return this.parseFragmentDefinition(); - case 'schema': - case 'scalar': - case 'type': - case 'interface': - case 'union': - case 'enum': - case 'input': - case 'directive': - return this.parseTypeSystemDefinition(); - case 'extend': - return this.parseTypeSystemExtension(); - } - } else if (this.peek(TokenKind.BRACE_L)) { - return this.parseOperationDefinition(); - } else if (this.peekDescription()) { - return this.parseTypeSystemDefinition(); - } - - throw this.unexpected(); - } - - // Implements the parsing rules in the Operations section. - - /** - * OperationDefinition : - * - SelectionSet - * - OperationType Name? VariableDefinitions? Directives? SelectionSet - */ - parseOperationDefinition(): OperationDefinitionNode { - const start = this._lexer.token; - if (this.peek(TokenKind.BRACE_L)) { - return { - kind: Kind.OPERATION_DEFINITION, - operation: 'query', - name: undefined, - variableDefinitions: [], - directives: [], - selectionSet: this.parseSelectionSet(), - loc: this.loc(start), - }; - } - const operation = this.parseOperationType(); - let name; - if (this.peek(TokenKind.NAME)) { - name = this.parseName(); - } - return { - kind: Kind.OPERATION_DEFINITION, - operation, - name, - variableDefinitions: this.parseVariableDefinitions(), - directives: this.parseDirectives(false), - selectionSet: this.parseSelectionSet(), - loc: this.loc(start), - }; - } - - /** - * OperationType : one of query mutation subscription - */ - parseOperationType(): OperationTypeNode { - const operationToken = this.expectToken(TokenKind.NAME); - switch (operationToken.value) { - case 'query': - return 'query'; - case 'mutation': - return 'mutation'; - case 'subscription': - return 'subscription'; - } - - throw this.unexpected(operationToken); - } - - /** - * VariableDefinitions : ( VariableDefinition+ ) - */ - parseVariableDefinitions(): Array<VariableDefinitionNode> { - return this.optionalMany( - TokenKind.PAREN_L, - this.parseVariableDefinition, - TokenKind.PAREN_R, - ); - } - - /** - * VariableDefinition : Variable : Type DefaultValue? Directives[Const]? - */ - parseVariableDefinition(): VariableDefinitionNode { - const start = this._lexer.token; - return { - kind: Kind.VARIABLE_DEFINITION, - variable: this.parseVariable(), - type: (this.expectToken(TokenKind.COLON), this.parseTypeReference()), - defaultValue: this.expectOptionalToken(TokenKind.EQUALS) - ? this.parseValueLiteral(true) - : undefined, - directives: this.parseDirectives(true), - loc: this.loc(start), - }; - } - - /** - * Variable : $ Name - */ - parseVariable(): VariableNode { - const start = this._lexer.token; - this.expectToken(TokenKind.DOLLAR); - return { - kind: Kind.VARIABLE, - name: this.parseName(), - loc: this.loc(start), - }; - } - - /** - * SelectionSet : { Selection+ } - */ - parseSelectionSet(): SelectionSetNode { - const start = this._lexer.token; - return { - kind: Kind.SELECTION_SET, - selections: this.many( - TokenKind.BRACE_L, - this.parseSelection, - TokenKind.BRACE_R, - ), - loc: this.loc(start), - }; - } - - /** - * Selection : - * - Field - * - FragmentSpread - * - InlineFragment - */ - parseSelection(): SelectionNode { - return this.peek(TokenKind.SPREAD) - ? this.parseFragment() - : this.parseField(); - } - - /** - * Field : Alias? Name Arguments? Directives? SelectionSet? - * - * Alias : Name : - */ - parseField(): FieldNode { - const start = this._lexer.token; - - const nameOrAlias = this.parseName(); - let alias; - let name; - if (this.expectOptionalToken(TokenKind.COLON)) { - alias = nameOrAlias; - name = this.parseName(); - } else { - name = nameOrAlias; - } - - return { - kind: Kind.FIELD, - alias, - name, - arguments: this.parseArguments(false), - directives: this.parseDirectives(false), - selectionSet: this.peek(TokenKind.BRACE_L) - ? this.parseSelectionSet() - : undefined, - loc: this.loc(start), - }; - } - - /** - * Arguments[Const] : ( Argument[?Const]+ ) - */ - parseArguments(isConst: boolean): Array<ArgumentNode> { - const item = isConst ? this.parseConstArgument : this.parseArgument; - return this.optionalMany(TokenKind.PAREN_L, item, TokenKind.PAREN_R); - } - - /** - * Argument[Const] : Name : Value[?Const] - */ - parseArgument(): ArgumentNode { - const start = this._lexer.token; - const name = this.parseName(); - - this.expectToken(TokenKind.COLON); - return { - kind: Kind.ARGUMENT, - name, - value: this.parseValueLiteral(false), - loc: this.loc(start), - }; - } - - parseConstArgument(): ArgumentNode { - const start = this._lexer.token; - return { - kind: Kind.ARGUMENT, - name: this.parseName(), - value: (this.expectToken(TokenKind.COLON), this.parseValueLiteral(true)), - loc: this.loc(start), - }; - } - - // Implements the parsing rules in the Fragments section. - - /** - * Corresponds to both FragmentSpread and InlineFragment in the spec. - * - * FragmentSpread : ... FragmentName Directives? - * - * InlineFragment : ... TypeCondition? Directives? SelectionSet - */ - parseFragment(): FragmentSpreadNode | InlineFragmentNode { - const start = this._lexer.token; - this.expectToken(TokenKind.SPREAD); - - const hasTypeCondition = this.expectOptionalKeyword('on'); - if (!hasTypeCondition && this.peek(TokenKind.NAME)) { - return { - kind: Kind.FRAGMENT_SPREAD, - name: this.parseFragmentName(), - directives: this.parseDirectives(false), - loc: this.loc(start), - }; - } - return { - kind: Kind.INLINE_FRAGMENT, - typeCondition: hasTypeCondition ? this.parseNamedType() : undefined, - directives: this.parseDirectives(false), - selectionSet: this.parseSelectionSet(), - loc: this.loc(start), - }; - } - - /** - * FragmentDefinition : - * - fragment FragmentName on TypeCondition Directives? SelectionSet - * - * TypeCondition : NamedType - */ - parseFragmentDefinition(): FragmentDefinitionNode { - const start = this._lexer.token; - this.expectKeyword('fragment'); - // Experimental support for defining variables within fragments changes - // the grammar of FragmentDefinition: - // - fragment FragmentName VariableDefinitions? on TypeCondition Directives? SelectionSet - if (this._options?.experimentalFragmentVariables === true) { - return { - kind: Kind.FRAGMENT_DEFINITION, - name: this.parseFragmentName(), - variableDefinitions: this.parseVariableDefinitions(), - typeCondition: (this.expectKeyword('on'), this.parseNamedType()), - directives: this.parseDirectives(false), - selectionSet: this.parseSelectionSet(), - loc: this.loc(start), - }; - } - return { - kind: Kind.FRAGMENT_DEFINITION, - name: this.parseFragmentName(), - typeCondition: (this.expectKeyword('on'), this.parseNamedType()), - directives: this.parseDirectives(false), - selectionSet: this.parseSelectionSet(), - loc: this.loc(start), - }; - } - - /** - * FragmentName : Name but not `on` - */ - parseFragmentName(): NameNode { - if (this._lexer.token.value === 'on') { - throw this.unexpected(); - } - return this.parseName(); - } - - // Implements the parsing rules in the Values section. - - /** - * Value[Const] : - * - [~Const] Variable - * - IntValue - * - FloatValue - * - StringValue - * - BooleanValue - * - NullValue - * - EnumValue - * - ListValue[?Const] - * - ObjectValue[?Const] - * - * BooleanValue : one of `true` `false` - * - * NullValue : `null` - * - * EnumValue : Name but not `true`, `false` or `null` - */ - parseValueLiteral(isConst: boolean): ValueNode { - const token = this._lexer.token; - switch (token.kind) { - case TokenKind.BRACKET_L: - return this.parseList(isConst); - case TokenKind.BRACE_L: - return this.parseObject(isConst); - case TokenKind.INT: - this._lexer.advance(); - return { - kind: Kind.INT, - value: ((token.value: any): string), - loc: this.loc(token), - }; - case TokenKind.FLOAT: - this._lexer.advance(); - return { - kind: Kind.FLOAT, - value: ((token.value: any): string), - loc: this.loc(token), - }; - case TokenKind.STRING: - case TokenKind.BLOCK_STRING: - return this.parseStringLiteral(); - case TokenKind.NAME: - this._lexer.advance(); - switch (token.value) { - case 'true': - return { kind: Kind.BOOLEAN, value: true, loc: this.loc(token) }; - case 'false': - return { kind: Kind.BOOLEAN, value: false, loc: this.loc(token) }; - case 'null': - return { kind: Kind.NULL, loc: this.loc(token) }; - default: - return { - kind: Kind.ENUM, - value: ((token.value: any): string), - loc: this.loc(token), - }; - } - case TokenKind.DOLLAR: - if (!isConst) { - return this.parseVariable(); - } - break; - } - throw this.unexpected(); - } - - parseStringLiteral(): StringValueNode { - const token = this._lexer.token; - this._lexer.advance(); - return { - kind: Kind.STRING, - value: ((token.value: any): string), - block: token.kind === TokenKind.BLOCK_STRING, - loc: this.loc(token), - }; - } - - /** - * ListValue[Const] : - * - [ ] - * - [ Value[?Const]+ ] - */ - parseList(isConst: boolean): ListValueNode { - const start = this._lexer.token; - const item = () => this.parseValueLiteral(isConst); - return { - kind: Kind.LIST, - values: this.any(TokenKind.BRACKET_L, item, TokenKind.BRACKET_R), - loc: this.loc(start), - }; - } - - /** - * ObjectValue[Const] : - * - { } - * - { ObjectField[?Const]+ } - */ - parseObject(isConst: boolean): ObjectValueNode { - const start = this._lexer.token; - const item = () => this.parseObjectField(isConst); - return { - kind: Kind.OBJECT, - fields: this.any(TokenKind.BRACE_L, item, TokenKind.BRACE_R), - loc: this.loc(start), - }; - } - - /** - * ObjectField[Const] : Name : Value[?Const] - */ - parseObjectField(isConst: boolean): ObjectFieldNode { - const start = this._lexer.token; - const name = this.parseName(); - this.expectToken(TokenKind.COLON); - - return { - kind: Kind.OBJECT_FIELD, - name, - value: this.parseValueLiteral(isConst), - loc: this.loc(start), - }; - } - - // Implements the parsing rules in the Directives section. - - /** - * Directives[Const] : Directive[?Const]+ - */ - parseDirectives(isConst: boolean): Array<DirectiveNode> { - const directives = []; - while (this.peek(TokenKind.AT)) { - directives.push(this.parseDirective(isConst)); - } - return directives; - } - - /** - * Directive[Const] : @ Name Arguments[?Const]? - */ - parseDirective(isConst: boolean): DirectiveNode { - const start = this._lexer.token; - this.expectToken(TokenKind.AT); - return { - kind: Kind.DIRECTIVE, - name: this.parseName(), - arguments: this.parseArguments(isConst), - loc: this.loc(start), - }; - } - - // Implements the parsing rules in the Types section. - - /** - * Type : - * - NamedType - * - ListType - * - NonNullType - */ - parseTypeReference(): TypeNode { - const start = this._lexer.token; - let type; - if (this.expectOptionalToken(TokenKind.BRACKET_L)) { - type = this.parseTypeReference(); - this.expectToken(TokenKind.BRACKET_R); - type = { - kind: Kind.LIST_TYPE, - type, - loc: this.loc(start), - }; - } else { - type = this.parseNamedType(); - } - - if (this.expectOptionalToken(TokenKind.BANG)) { - return { - kind: Kind.NON_NULL_TYPE, - type, - loc: this.loc(start), - }; - } - return type; - } - - /** - * NamedType : Name - */ - parseNamedType(): NamedTypeNode { - const start = this._lexer.token; - return { - kind: Kind.NAMED_TYPE, - name: this.parseName(), - loc: this.loc(start), - }; - } - - // Implements the parsing rules in the Type Definition section. - - /** - * TypeSystemDefinition : - * - SchemaDefinition - * - TypeDefinition - * - DirectiveDefinition - * - * TypeDefinition : - * - ScalarTypeDefinition - * - ObjectTypeDefinition - * - InterfaceTypeDefinition - * - UnionTypeDefinition - * - EnumTypeDefinition - * - InputObjectTypeDefinition - */ - parseTypeSystemDefinition(): TypeSystemDefinitionNode { - // Many definitions begin with a description and require a lookahead. - const keywordToken = this.peekDescription() - ? this._lexer.lookahead() - : this._lexer.token; - - if (keywordToken.kind === TokenKind.NAME) { - switch (keywordToken.value) { - case 'schema': - return this.parseSchemaDefinition(); - case 'scalar': - return this.parseScalarTypeDefinition(); - case 'type': - return this.parseObjectTypeDefinition(); - case 'interface': - return this.parseInterfaceTypeDefinition(); - case 'union': - return this.parseUnionTypeDefinition(); - case 'enum': - return this.parseEnumTypeDefinition(); - case 'input': - return this.parseInputObjectTypeDefinition(); - case 'directive': - return this.parseDirectiveDefinition(); - } - } - - throw this.unexpected(keywordToken); - } - - peekDescription(): boolean { - return this.peek(TokenKind.STRING) || this.peek(TokenKind.BLOCK_STRING); - } - - /** - * Description : StringValue - */ - parseDescription(): void | StringValueNode { - if (this.peekDescription()) { - return this.parseStringLiteral(); - } - } - - /** - * SchemaDefinition : Description? schema Directives[Const]? { OperationTypeDefinition+ } - */ - parseSchemaDefinition(): SchemaDefinitionNode { - const start = this._lexer.token; - const description = this.parseDescription(); - this.expectKeyword('schema'); - const directives = this.parseDirectives(true); - const operationTypes = this.many( - TokenKind.BRACE_L, - this.parseOperationTypeDefinition, - TokenKind.BRACE_R, - ); - return { - kind: Kind.SCHEMA_DEFINITION, - description, - directives, - operationTypes, - loc: this.loc(start), - }; - } - - /** - * OperationTypeDefinition : OperationType : NamedType - */ - parseOperationTypeDefinition(): OperationTypeDefinitionNode { - const start = this._lexer.token; - const operation = this.parseOperationType(); - this.expectToken(TokenKind.COLON); - const type = this.parseNamedType(); - return { - kind: Kind.OPERATION_TYPE_DEFINITION, - operation, - type, - loc: this.loc(start), - }; - } - - /** - * ScalarTypeDefinition : Description? scalar Name Directives[Const]? - */ - parseScalarTypeDefinition(): ScalarTypeDefinitionNode { - const start = this._lexer.token; - const description = this.parseDescription(); - this.expectKeyword('scalar'); - const name = this.parseName(); - const directives = this.parseDirectives(true); - return { - kind: Kind.SCALAR_TYPE_DEFINITION, - description, - name, - directives, - loc: this.loc(start), - }; - } - - /** - * ObjectTypeDefinition : - * Description? - * type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition? - */ - parseObjectTypeDefinition(): ObjectTypeDefinitionNode { - const start = this._lexer.token; - const description = this.parseDescription(); - this.expectKeyword('type'); - const name = this.parseName(); - const interfaces = this.parseImplementsInterfaces(); - const directives = this.parseDirectives(true); - const fields = this.parseFieldsDefinition(); - return { - kind: Kind.OBJECT_TYPE_DEFINITION, - description, - name, - interfaces, - directives, - fields, - loc: this.loc(start), - }; - } - - /** - * ImplementsInterfaces : - * - implements `&`? NamedType - * - ImplementsInterfaces & NamedType - */ - parseImplementsInterfaces(): Array<NamedTypeNode> { - if (!this.expectOptionalKeyword('implements')) { - return []; - } - - if (this._options?.allowLegacySDLImplementsInterfaces === true) { - const types = []; - // Optional leading ampersand - this.expectOptionalToken(TokenKind.AMP); - do { - types.push(this.parseNamedType()); - } while ( - this.expectOptionalToken(TokenKind.AMP) || - this.peek(TokenKind.NAME) - ); - return types; - } - - return this.delimitedMany(TokenKind.AMP, this.parseNamedType); - } - - /** - * FieldsDefinition : { FieldDefinition+ } - */ - parseFieldsDefinition(): Array<FieldDefinitionNode> { - // Legacy support for the SDL? - if ( - this._options?.allowLegacySDLEmptyFields === true && - this.peek(TokenKind.BRACE_L) && - this._lexer.lookahead().kind === TokenKind.BRACE_R - ) { - this._lexer.advance(); - this._lexer.advance(); - return []; - } - return this.optionalMany( - TokenKind.BRACE_L, - this.parseFieldDefinition, - TokenKind.BRACE_R, - ); - } - - /** - * FieldDefinition : - * - Description? Name ArgumentsDefinition? : Type Directives[Const]? - */ - parseFieldDefinition(): FieldDefinitionNode { - const start = this._lexer.token; - const description = this.parseDescription(); - const name = this.parseName(); - const args = this.parseArgumentDefs(); - this.expectToken(TokenKind.COLON); - const type = this.parseTypeReference(); - const directives = this.parseDirectives(true); - return { - kind: Kind.FIELD_DEFINITION, - description, - name, - arguments: args, - type, - directives, - loc: this.loc(start), - }; - } - - /** - * ArgumentsDefinition : ( InputValueDefinition+ ) - */ - parseArgumentDefs(): Array<InputValueDefinitionNode> { - return this.optionalMany( - TokenKind.PAREN_L, - this.parseInputValueDef, - TokenKind.PAREN_R, - ); - } - - /** - * InputValueDefinition : - * - Description? Name : Type DefaultValue? Directives[Const]? - */ - parseInputValueDef(): InputValueDefinitionNode { - const start = this._lexer.token; - const description = this.parseDescription(); - const name = this.parseName(); - this.expectToken(TokenKind.COLON); - const type = this.parseTypeReference(); - let defaultValue; - if (this.expectOptionalToken(TokenKind.EQUALS)) { - defaultValue = this.parseValueLiteral(true); - } - const directives = this.parseDirectives(true); - return { - kind: Kind.INPUT_VALUE_DEFINITION, - description, - name, - type, - defaultValue, - directives, - loc: this.loc(start), - }; - } - - /** - * InterfaceTypeDefinition : - * - Description? interface Name Directives[Const]? FieldsDefinition? - */ - parseInterfaceTypeDefinition(): InterfaceTypeDefinitionNode { - const start = this._lexer.token; - const description = this.parseDescription(); - this.expectKeyword('interface'); - const name = this.parseName(); - const interfaces = this.parseImplementsInterfaces(); - const directives = this.parseDirectives(true); - const fields = this.parseFieldsDefinition(); - return { - kind: Kind.INTERFACE_TYPE_DEFINITION, - description, - name, - interfaces, - directives, - fields, - loc: this.loc(start), - }; - } - - /** - * UnionTypeDefinition : - * - Description? union Name Directives[Const]? UnionMemberTypes? - */ - parseUnionTypeDefinition(): UnionTypeDefinitionNode { - const start = this._lexer.token; - const description = this.parseDescription(); - this.expectKeyword('union'); - const name = this.parseName(); - const directives = this.parseDirectives(true); - const types = this.parseUnionMemberTypes(); - return { - kind: Kind.UNION_TYPE_DEFINITION, - description, - name, - directives, - types, - loc: this.loc(start), - }; - } - - /** - * UnionMemberTypes : - * - = `|`? NamedType - * - UnionMemberTypes | NamedType - */ - parseUnionMemberTypes(): Array<NamedTypeNode> { - return this.expectOptionalToken(TokenKind.EQUALS) - ? this.delimitedMany(TokenKind.PIPE, this.parseNamedType) - : []; - } - - /** - * EnumTypeDefinition : - * - Description? enum Name Directives[Const]? EnumValuesDefinition? - */ - parseEnumTypeDefinition(): EnumTypeDefinitionNode { - const start = this._lexer.token; - const description = this.parseDescription(); - this.expectKeyword('enum'); - const name = this.parseName(); - const directives = this.parseDirectives(true); - const values = this.parseEnumValuesDefinition(); - return { - kind: Kind.ENUM_TYPE_DEFINITION, - description, - name, - directives, - values, - loc: this.loc(start), - }; - } - - /** - * EnumValuesDefinition : { EnumValueDefinition+ } - */ - parseEnumValuesDefinition(): Array<EnumValueDefinitionNode> { - return this.optionalMany( - TokenKind.BRACE_L, - this.parseEnumValueDefinition, - TokenKind.BRACE_R, - ); - } - - /** - * EnumValueDefinition : Description? EnumValue Directives[Const]? - * - * EnumValue : Name - */ - parseEnumValueDefinition(): EnumValueDefinitionNode { - const start = this._lexer.token; - const description = this.parseDescription(); - const name = this.parseName(); - const directives = this.parseDirectives(true); - return { - kind: Kind.ENUM_VALUE_DEFINITION, - description, - name, - directives, - loc: this.loc(start), - }; - } - - /** - * InputObjectTypeDefinition : - * - Description? input Name Directives[Const]? InputFieldsDefinition? - */ - parseInputObjectTypeDefinition(): InputObjectTypeDefinitionNode { - const start = this._lexer.token; - const description = this.parseDescription(); - this.expectKeyword('input'); - const name = this.parseName(); - const directives = this.parseDirectives(true); - const fields = this.parseInputFieldsDefinition(); - return { - kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, - description, - name, - directives, - fields, - loc: this.loc(start), - }; - } - - /** - * InputFieldsDefinition : { InputValueDefinition+ } - */ - parseInputFieldsDefinition(): Array<InputValueDefinitionNode> { - return this.optionalMany( - TokenKind.BRACE_L, - this.parseInputValueDef, - TokenKind.BRACE_R, - ); - } - - /** - * TypeSystemExtension : - * - SchemaExtension - * - TypeExtension - * - * TypeExtension : - * - ScalarTypeExtension - * - ObjectTypeExtension - * - InterfaceTypeExtension - * - UnionTypeExtension - * - EnumTypeExtension - * - InputObjectTypeDefinition - */ - parseTypeSystemExtension(): TypeSystemExtensionNode { - const keywordToken = this._lexer.lookahead(); - - if (keywordToken.kind === TokenKind.NAME) { - switch (keywordToken.value) { - case 'schema': - return this.parseSchemaExtension(); - case 'scalar': - return this.parseScalarTypeExtension(); - case 'type': - return this.parseObjectTypeExtension(); - case 'interface': - return this.parseInterfaceTypeExtension(); - case 'union': - return this.parseUnionTypeExtension(); - case 'enum': - return this.parseEnumTypeExtension(); - case 'input': - return this.parseInputObjectTypeExtension(); - } - } - - throw this.unexpected(keywordToken); - } - - /** - * SchemaExtension : - * - extend schema Directives[Const]? { OperationTypeDefinition+ } - * - extend schema Directives[Const] - */ - parseSchemaExtension(): SchemaExtensionNode { - const start = this._lexer.token; - this.expectKeyword('extend'); - this.expectKeyword('schema'); - const directives = this.parseDirectives(true); - const operationTypes = this.optionalMany( - TokenKind.BRACE_L, - this.parseOperationTypeDefinition, - TokenKind.BRACE_R, - ); - if (directives.length === 0 && operationTypes.length === 0) { - throw this.unexpected(); - } - return { - kind: Kind.SCHEMA_EXTENSION, - directives, - operationTypes, - loc: this.loc(start), - }; - } - - /** - * ScalarTypeExtension : - * - extend scalar Name Directives[Const] - */ - parseScalarTypeExtension(): ScalarTypeExtensionNode { - const start = this._lexer.token; - this.expectKeyword('extend'); - this.expectKeyword('scalar'); - const name = this.parseName(); - const directives = this.parseDirectives(true); - if (directives.length === 0) { - throw this.unexpected(); - } - return { - kind: Kind.SCALAR_TYPE_EXTENSION, - name, - directives, - loc: this.loc(start), - }; - } - - /** - * ObjectTypeExtension : - * - extend type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition - * - extend type Name ImplementsInterfaces? Directives[Const] - * - extend type Name ImplementsInterfaces - */ - parseObjectTypeExtension(): ObjectTypeExtensionNode { - const start = this._lexer.token; - this.expectKeyword('extend'); - this.expectKeyword('type'); - const name = this.parseName(); - const interfaces = this.parseImplementsInterfaces(); - const directives = this.parseDirectives(true); - const fields = this.parseFieldsDefinition(); - if ( - interfaces.length === 0 && - directives.length === 0 && - fields.length === 0 - ) { - throw this.unexpected(); - } - return { - kind: Kind.OBJECT_TYPE_EXTENSION, - name, - interfaces, - directives, - fields, - loc: this.loc(start), - }; - } - - /** - * InterfaceTypeExtension : - * - extend interface Name ImplementsInterfaces? Directives[Const]? FieldsDefinition - * - extend interface Name ImplementsInterfaces? Directives[Const] - * - extend interface Name ImplementsInterfaces - */ - parseInterfaceTypeExtension(): InterfaceTypeExtensionNode { - const start = this._lexer.token; - this.expectKeyword('extend'); - this.expectKeyword('interface'); - const name = this.parseName(); - const interfaces = this.parseImplementsInterfaces(); - const directives = this.parseDirectives(true); - const fields = this.parseFieldsDefinition(); - if ( - interfaces.length === 0 && - directives.length === 0 && - fields.length === 0 - ) { - throw this.unexpected(); - } - return { - kind: Kind.INTERFACE_TYPE_EXTENSION, - name, - interfaces, - directives, - fields, - loc: this.loc(start), - }; - } - - /** - * UnionTypeExtension : - * - extend union Name Directives[Const]? UnionMemberTypes - * - extend union Name Directives[Const] - */ - parseUnionTypeExtension(): UnionTypeExtensionNode { - const start = this._lexer.token; - this.expectKeyword('extend'); - this.expectKeyword('union'); - const name = this.parseName(); - const directives = this.parseDirectives(true); - const types = this.parseUnionMemberTypes(); - if (directives.length === 0 && types.length === 0) { - throw this.unexpected(); - } - return { - kind: Kind.UNION_TYPE_EXTENSION, - name, - directives, - types, - loc: this.loc(start), - }; - } - - /** - * EnumTypeExtension : - * - extend enum Name Directives[Const]? EnumValuesDefinition - * - extend enum Name Directives[Const] - */ - parseEnumTypeExtension(): EnumTypeExtensionNode { - const start = this._lexer.token; - this.expectKeyword('extend'); - this.expectKeyword('enum'); - const name = this.parseName(); - const directives = this.parseDirectives(true); - const values = this.parseEnumValuesDefinition(); - if (directives.length === 0 && values.length === 0) { - throw this.unexpected(); - } - return { - kind: Kind.ENUM_TYPE_EXTENSION, - name, - directives, - values, - loc: this.loc(start), - }; - } - - /** - * InputObjectTypeExtension : - * - extend input Name Directives[Const]? InputFieldsDefinition - * - extend input Name Directives[Const] - */ - parseInputObjectTypeExtension(): InputObjectTypeExtensionNode { - const start = this._lexer.token; - this.expectKeyword('extend'); - this.expectKeyword('input'); - const name = this.parseName(); - const directives = this.parseDirectives(true); - const fields = this.parseInputFieldsDefinition(); - if (directives.length === 0 && fields.length === 0) { - throw this.unexpected(); - } - return { - kind: Kind.INPUT_OBJECT_TYPE_EXTENSION, - name, - directives, - fields, - loc: this.loc(start), - }; - } - - /** - * DirectiveDefinition : - * - Description? directive @ Name ArgumentsDefinition? `repeatable`? on DirectiveLocations - */ - parseDirectiveDefinition(): DirectiveDefinitionNode { - const start = this._lexer.token; - const description = this.parseDescription(); - this.expectKeyword('directive'); - this.expectToken(TokenKind.AT); - const name = this.parseName(); - const args = this.parseArgumentDefs(); - const repeatable = this.expectOptionalKeyword('repeatable'); - this.expectKeyword('on'); - const locations = this.parseDirectiveLocations(); - return { - kind: Kind.DIRECTIVE_DEFINITION, - description, - name, - arguments: args, - repeatable, - locations, - loc: this.loc(start), - }; - } - - /** - * DirectiveLocations : - * - `|`? DirectiveLocation - * - DirectiveLocations | DirectiveLocation - */ - parseDirectiveLocations(): Array<NameNode> { - return this.delimitedMany(TokenKind.PIPE, this.parseDirectiveLocation); - } - - /* - * DirectiveLocation : - * - ExecutableDirectiveLocation - * - TypeSystemDirectiveLocation - * - * ExecutableDirectiveLocation : one of - * `QUERY` - * `MUTATION` - * `SUBSCRIPTION` - * `FIELD` - * `FRAGMENT_DEFINITION` - * `FRAGMENT_SPREAD` - * `INLINE_FRAGMENT` - * - * TypeSystemDirectiveLocation : one of - * `SCHEMA` - * `SCALAR` - * `OBJECT` - * `FIELD_DEFINITION` - * `ARGUMENT_DEFINITION` - * `INTERFACE` - * `UNION` - * `ENUM` - * `ENUM_VALUE` - * `INPUT_OBJECT` - * `INPUT_FIELD_DEFINITION` - */ - parseDirectiveLocation(): NameNode { - const start = this._lexer.token; - const name = this.parseName(); - if (DirectiveLocation[name.value] !== undefined) { - return name; - } - throw this.unexpected(start); - } - - // Core parsing utility functions - - /** - * Returns a location object, used to identify the place in the source that created a given parsed object. - */ - loc(startToken: Token): Location | void { - if (this._options?.noLocation !== true) { - return new Location( - startToken, - this._lexer.lastToken, - this._lexer.source, - ); - } - } - - /** - * Determines if the next token is of a given kind - */ - peek(kind: TokenKindEnum): boolean { - return this._lexer.token.kind === kind; - } - - /** - * If the next token is of the given kind, return that token after advancing the lexer. - * Otherwise, do not change the parser state and throw an error. - */ - expectToken(kind: TokenKindEnum): Token { - const token = this._lexer.token; - if (token.kind === kind) { - this._lexer.advance(); - return token; - } - - throw syntaxError( - this._lexer.source, - token.start, - `Expected ${getTokenKindDesc(kind)}, found ${getTokenDesc(token)}.`, - ); - } - - /** - * 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 { - const token = this._lexer.token; - if (token.kind === kind) { - this._lexer.advance(); - return token; - } - return undefined; - } - - /** - * If the next token is a given keyword, advance the lexer. - * Otherwise, do not change the parser state and throw an error. - */ - expectKeyword(value: string) { - const token = this._lexer.token; - if (token.kind === TokenKind.NAME && token.value === value) { - this._lexer.advance(); - } else { - throw syntaxError( - this._lexer.source, - token.start, - `Expected "${value}", found ${getTokenDesc(token)}.`, - ); - } - } - - /** - * If the next token is a given keyword, return "true" after advancing the lexer. - * Otherwise, do not change the parser state and return "false". - */ - expectOptionalKeyword(value: string): boolean { - const token = this._lexer.token; - if (token.kind === TokenKind.NAME && token.value === value) { - this._lexer.advance(); - return true; - } - return false; - } - - /** - * Helper function for creating an error when an unexpected lexed token is encountered. - */ - unexpected(atToken?: ?Token): GraphQLError { - const token = atToken ?? this._lexer.token; - return syntaxError( - this._lexer.source, - token.start, - `Unexpected ${getTokenDesc(token)}.`, - ); - } - - /** - * Returns a possibly empty list of parse nodes, determined by the parseFn. - * This list begins with a lex token of openKind and ends with a lex token of closeKind. - * Advances the parser to the next lex token after the closing token. - */ - any<T>( - openKind: TokenKindEnum, - parseFn: () => T, - closeKind: TokenKindEnum, - ): Array<T> { - this.expectToken(openKind); - const nodes = []; - while (!this.expectOptionalToken(closeKind)) { - nodes.push(parseFn.call(this)); - } - return nodes; - } - - /** - * Returns a list of parse nodes, determined by the parseFn. - * It can be empty only if open token is missing otherwise it will always return non-empty list - * that begins with a lex token of openKind and ends with a lex token of closeKind. - * Advances the parser to the next lex token after the closing token. - */ - optionalMany<T>( - openKind: TokenKindEnum, - parseFn: () => T, - closeKind: TokenKindEnum, - ): Array<T> { - if (this.expectOptionalToken(openKind)) { - const nodes = []; - do { - nodes.push(parseFn.call(this)); - } while (!this.expectOptionalToken(closeKind)); - return nodes; - } - return []; - } - - /** - * Returns a non-empty list of parse nodes, determined by the parseFn. - * This list begins with a lex token of openKind and ends with a lex token of closeKind. - * Advances the parser to the next lex token after the closing token. - */ - many<T>( - openKind: TokenKindEnum, - parseFn: () => T, - closeKind: TokenKindEnum, - ): Array<T> { - this.expectToken(openKind); - const nodes = []; - do { - nodes.push(parseFn.call(this)); - } while (!this.expectOptionalToken(closeKind)); - return nodes; - } - - /** - * Returns a non-empty list of parse nodes, determined by the parseFn. - * This list may begin with a lex token of delimiterKind followed by items separated by lex tokens of tokenKind. - * Advances the parser to the next lex token after last item in the list. - */ - delimitedMany<T>(delimiterKind: TokenKindEnum, parseFn: () => T): Array<T> { - this.expectOptionalToken(delimiterKind); - - const nodes = []; - do { - nodes.push(parseFn.call(this)); - } while (this.expectOptionalToken(delimiterKind)); - return nodes; - } -} - -/** - * A helper function to describe a token as a string for debugging. - */ -function getTokenDesc(token: Token): string { - const value = token.value; - return getTokenKindDesc(token.kind) + (value != null ? ` "${value}"` : ''); -} - -/** - * A helper function to describe a token kind as a string for debugging. - */ -function getTokenKindDesc(kind: TokenKindEnum): string { - return isPunctuatorTokenKind(kind) ? `"${kind}"` : kind; -} |