diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index 92f222cb3..22dab575e 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -43,7 +43,14 @@ Token :: - FloatValue - StringValue -Punctuator :: one of ! $ & ( ) ... : = @ [ ] { | } +Punctuator :: + +- DotPunctuator +- OtherPunctuator + +DotPunctuator :: `.` [lookahead != {`.`, Digit}] + +OtherPunctuator :: one of ! $ & ( ) ... : = @ [ ] { | } Name :: @@ -412,3 +419,11 @@ TypeSystemDirectiveLocation : one of - `ENUM_VALUE` - `INPUT_OBJECT` - `INPUT_FIELD_DEFINITION` + +SchemaCoordinate : + +- Name +- Name . Name +- Name . Name ( Name : ) +- @ Name +- @ Name ( Name : ) diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index 76b5fadcb..3c22f0e71 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -176,12 +176,25 @@ and is {Ignored}. ### Punctuators -Punctuator :: one of ! $ & ( ) ... : = @ [ ] { | } +Punctuator :: + +- DotPunctuator +- OtherPunctuator + +DotPunctuator :: `.` [lookahead != {`.`, Digit}] + +OtherPunctuator :: one of ! $ & ( ) ... : = @ [ ] { | } GraphQL documents include punctuation in order to describe structure. GraphQL is a data description language and not a programming language, therefore GraphQL lacks the punctuation often used to describe mathematical expressions. +The {`.`} punctuator must not be followed by a {`.`} or {Digit}. This ensures +that the source {"..."} can only be interpreted as a single {`...`} and not +three {`.`}. It also avoids any potential ambiguity with {FloatValue}. As an +example the source {".123"} has no valid lexical representation (without this +restriction it would have been interpreted as {`.`} followed by {IntValue}). + ### Names Name :: diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 1348899fb..ef1eeea43 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -2164,3 +2164,128 @@ to the relevant IETF specification. ```graphql example scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122") ``` + +## Schema Coordinates + +SchemaCoordinate : + +- Name +- Name . Name +- Name . Name ( Name : ) +- @ Name +- @ Name ( Name : ) + +:: A _schema coordinate_ is a human readable string that uniquely identifies a +_schema element_ within a GraphQL Schema. + +:: A _schema element_ is a specific instance of a named type, field, input +field, enum value, field argument, directive, or directive argument. + +A _schema coordinate_ is always unique. Each _schema element_ may be referenced +by exactly one possible schema coordinate. + +A _schema coordinate_ may refer to either a defined or built-in _schema +element_. For example, `String` and `@deprecated(reason:)` are both valid schema +coordinates which refer to built-in schema elements. However it must not refer +to a meta-field. For example, `Business.__typename` is _not_ a valid schema +coordinate. + +Note: A union member is not a valid _schema coordinate_ as they reference +existing types in the schema. This preserves the uniqueness property of a +_schema coordinate_ as stated above. + +Note: A {SchemaCoordinate} is not a definition within a GraphQL {Document}, but +a separate standalone grammar, intended to be used by tools to reference types, +fields, and other *schema element*s. Examples include: as references within +documentation to refer to types and fields in a schema, a lookup key that can be +used in logging tools to track how often particular fields are queried in +production. + +**Semantics** + +To refer to a _schema element_, a _schema coordinate_ must be interpreted in the +context of a GraphQL {schema}. + +SchemaCoordinate : Name + +1. Let {typeName} be the value of the first {Name}. +2. Return the type in the {schema} named {typeName}. + +SchemaCoordinate : Name . Name + +1. Let {typeName} be the value of the first {Name}. +2. Let {type} be the type in the {schema} named {typeName}. +3. If {type} is an Enum type: +4. Let {enumValueName} be the value of the second {Name}. +5. Return the enum value of {type} named {enumValueName}. +6. Otherwise if {type} is an Input Object type: +7. Let {inputFieldName} be the value of the second {Name}. +8. Return the input field of {type} named {inputFieldName}. +9. Otherwise: +10. Assert {type} must be an Object or Interface type. +11. Let {fieldName} be the value of the second {Name}. +12. Return the field of {type} named {fieldName}. + +SchemaCoordinate : Name . Name ( Name : ) + +1. Let {typeName} be the value of the first {Name}. +2. Let {type} be the type in the {schema} named {typeName}. +3. Assert {type} must be an Object or Interface type. +4. Let {fieldName} be the value of the second {Name}. +5. Let {field} be the field of {type} named {fieldName}. +6. Assert {field} must exist. +7. Let {fieldArgumentName} be the value of the third {Name}. +8. Return the argument of {field} named {fieldArgumentName}. + +SchemaCoordinate : @ Name + +1. Let {directiveName} be the value of the first {Name}. +2. Return the directive in the {schema} named {directiveName}. + +SchemaCoordinate : @ Name ( Name : ) + +1. Let {directiveName} be the value of the first {Name}. +2. Let {directive} be the directive in the {schema} named {directiveName}. +3. Assert {directive} must exist. +4. Let {directiveArgumentName} be the value of the second {Name}. +5. Return the argument of {directive} named {directiveArgumentName}. + +**Examples** + +| Element Kind | _Schema Coordinate_ | _Schema Element_ | +| ------------------ | --------------------------------- | --------------------------------------------------------------------- | +| Named Type | `Business` | `Business` type | +| Field | `Business.name` | `name` field on the `Business` type | +| Input Field | `SearchCriteria.filter` | `filter` input field on the `SearchCriteria` input object type | +| Enum Value | `SearchFilter.OPEN_NOW` | `OPEN_NOW` value of the `SearchFilter` enum | +| Field Argument | `Query.searchBusiness(criteria:)` | `criteria` argument on the `searchBusiness` field on the `Query` type | +| Directive | `@private` | `@private` directive | +| Directive Argument | `@private(scope:)` | `scope` argument on the `@private` directive | + +The table above shows an example of a _schema coordinate_ for every kind of +_schema element_ based on the schema below. + +```graphql +type Query { + searchBusiness(criteria: SearchCriteria!): [Business] +} + +input SearchCriteria { + name: String + filter: SearchFilter +} + +enum SearchFilter { + OPEN_NOW + DELIVERS_TAKEOUT + VEGETARIAN_MENU +} + +type Business { + id: ID + name: String + email: String @private(scope: "loggedIn") +} + +directive @private(scope: String!) on FIELD_DEFINITION +```