diff --git a/examples/strict-semantic-nullability/schema.graphql b/examples/strict-semantic-nullability/schema.graphql index 6a5d1b06..ab79bc9e 100644 --- a/examples/strict-semantic-nullability/schema.graphql +++ b/examples/strict-semantic-nullability/schema.graphql @@ -1,42 +1,37 @@ # Schema generated by Grats (https://grats.capt.dev) # Do not manually edit. Regenerate by running `npx grats`. """ -Indicates that a field is only null if there is a matching error in the `errors` array. -In all other cases, the field is non-null. +Indicates that a position is semantically non null: it is only null if there is a matching error in the `errors` array. +In all other cases, the position is non-null. -Tools doing code generation may use this information to generate the field as non-null. - -This directive can be applied on field definitions: +Tools doing code generation may use this information to generate the position as non-null if field errors are handled out of band: ```graphql type User { + # email is semantically non-null and can be generated as non-null by error-handling clients. email: String @semanticNonNull } ``` -It can also be applied on object type extensions for use in client applications that do -not own the base schema: +The `levels` argument indicates what levels are semantically non null in case of lists: ```graphql -extend type User @semanticNonNull(field: "email") -``` +type User { + # friends is semantically non null + friends: [User] @semanticNonNull # same as @semanticNonNull(levels: [0]) -Control over list items is done using the `level` argument: + # every friends[k] is semantically non null + friends: [User] @semanticNonNull(levels: [1]) -```graphql -type User { - # friends is nullable but friends[0] is null only on errors - friends: [User] @semanticNonNull(level: 1) + # friends as well as every friends[k] is semantically non null + friends: [User] @semanticNonNull(levels: [0, 1]) } ``` -The `field` argument is the name of the field if `@semanticNonNull` is applied to an object definition. -If `@semanticNonNull` is applied to a field definition, `field` must be null. - -The `level` argument can be used to indicate what level is semantically non null in case of lists. -`level` starts at 0 if there is no list. If `level` is null, all levels are semantically non null. +`levels` are zero indexed. +Passing a negative level or a level greater than the list dimension is an error. """ -directive @semanticNonNull(field: String = null, level: Int = null) repeatable on FIELD_DEFINITION | OBJECT +directive @semanticNonNull(levels: [Int] = [0]) on FIELD_DEFINITION interface IPerson { name: String @semanticNonNull diff --git a/src/publicDirectives.ts b/src/publicDirectives.ts index dd9a1680..a025cd94 100644 --- a/src/publicDirectives.ts +++ b/src/publicDirectives.ts @@ -15,45 +15,40 @@ import { export const SEMANTIC_NON_NULL_DIRECTIVE = "semanticNonNull"; -// Copied from https://github.com/apollographql/specs/blob/ec27a720e588a8531315c37eda85b668fd612199/nullability/v0.1/nullability-v0.1.graphql#L11 +// Copied from https://github.com/apollographql/specs/blob/2a22ccf054994392a1b14d8810787cb27baee040/nullability/v0.2/nullability-v0.2.graphql#L1C1-L33C68 export const DIRECTIVES_AST: DocumentNode = parse(` """ -Indicates that a field is only null if there is a matching error in the \`errors\` array. -In all other cases, the field is non-null. +Indicates that a position is semantically non null: it is only null if there is a matching error in the \`errors\` array. +In all other cases, the position is non-null. -Tools doing code generation may use this information to generate the field as non-null. - -This directive can be applied on field definitions: +Tools doing code generation may use this information to generate the position as non-null if field errors are handled out of band: \`\`\`graphql type User { + # email is semantically non-null and can be generated as non-null by error-handling clients. email: String @semanticNonNull } \`\`\` -It can also be applied on object type extensions for use in client applications that do -not own the base schema: +The \`levels\` argument indicates what levels are semantically non null in case of lists: \`\`\`graphql -extend type User @semanticNonNull(field: "email") -\`\`\` +type User { + # friends is semantically non null + friends: [User] @semanticNonNull # same as @semanticNonNull(levels: [0]) -Control over list items is done using the \`level\` argument: + # every friends[k] is semantically non null + friends: [User] @semanticNonNull(levels: [1]) -\`\`\`graphql -type User { - # friends is nullable but friends[0] is null only on errors - friends: [User] @semanticNonNull(level: 1) + # friends as well as every friends[k] is semantically non null + friends: [User] @semanticNonNull(levels: [0, 1]) } \`\`\` -The \`field\` argument is the name of the field if \`@semanticNonNull\` is applied to an object definition. -If \`@semanticNonNull\` is applied to a field definition, \`field\` must be null. - -The \`level\` argument can be used to indicate what level is semantically non null in case of lists. -\`level\` starts at 0 if there is no list. If \`level\` is null, all levels are semantically non null. +\`levels\` are zero indexed. +Passing a negative level or a level greater than the list dimension is an error. """ -directive @semanticNonNull(field: String = null, level: Int = null) repeatable on FIELD_DEFINITION | OBJECT +directive @semanticNonNull(levels: [Int] = [0]) on FIELD_DEFINITION `); export function addSemanticNonNullDirective( diff --git a/src/tests/fixtures/semantic_nullability/semanticNonNull.ts.expected b/src/tests/fixtures/semantic_nullability/semanticNonNull.ts.expected index 458a8ad6..863186af 100644 --- a/src/tests/fixtures/semantic_nullability/semanticNonNull.ts.expected +++ b/src/tests/fixtures/semantic_nullability/semanticNonNull.ts.expected @@ -19,42 +19,37 @@ OUTPUT ----------------- -- SDL -- """ -Indicates that a field is only null if there is a matching error in the `errors` array. -In all other cases, the field is non-null. +Indicates that a position is semantically non null: it is only null if there is a matching error in the `errors` array. +In all other cases, the position is non-null. -Tools doing code generation may use this information to generate the field as non-null. - -This directive can be applied on field definitions: +Tools doing code generation may use this information to generate the position as non-null if field errors are handled out of band: ```graphql type User { + # email is semantically non-null and can be generated as non-null by error-handling clients. email: String @semanticNonNull } ``` -It can also be applied on object type extensions for use in client applications that do -not own the base schema: +The `levels` argument indicates what levels are semantically non null in case of lists: ```graphql -extend type User @semanticNonNull(field: "email") -``` +type User { + # friends is semantically non null + friends: [User] @semanticNonNull # same as @semanticNonNull(levels: [0]) -Control over list items is done using the `level` argument: + # every friends[k] is semantically non null + friends: [User] @semanticNonNull(levels: [1]) -```graphql -type User { - # friends is nullable but friends[0] is null only on errors - friends: [User] @semanticNonNull(level: 1) + # friends as well as every friends[k] is semantically non null + friends: [User] @semanticNonNull(levels: [0, 1]) } ``` -The `field` argument is the name of the field if `@semanticNonNull` is applied to an object definition. -If `@semanticNonNull` is applied to a field definition, `field` must be null. - -The `level` argument can be used to indicate what level is semantically non null in case of lists. -`level` starts at 0 if there is no list. If `level` is null, all levels are semantically non null. +`levels` are zero indexed. +Passing a negative level or a level greater than the list dimension is an error. """ -directive @semanticNonNull(field: String = null, level: Int = null) repeatable on FIELD_DEFINITION | OBJECT +directive @semanticNonNull(levels: [Int] = [0]) on FIELD_DEFINITION type User { name: String @metadata(argCount: 0) @semanticNonNull diff --git a/src/tests/fixtures/semantic_nullability/semanticNonNullMatchesInterface.ts.expected b/src/tests/fixtures/semantic_nullability/semanticNonNullMatchesInterface.ts.expected index a2d0e046..c490d8ac 100644 --- a/src/tests/fixtures/semantic_nullability/semanticNonNullMatchesInterface.ts.expected +++ b/src/tests/fixtures/semantic_nullability/semanticNonNullMatchesInterface.ts.expected @@ -26,42 +26,37 @@ OUTPUT ----------------- -- SDL -- """ -Indicates that a field is only null if there is a matching error in the `errors` array. -In all other cases, the field is non-null. +Indicates that a position is semantically non null: it is only null if there is a matching error in the `errors` array. +In all other cases, the position is non-null. -Tools doing code generation may use this information to generate the field as non-null. - -This directive can be applied on field definitions: +Tools doing code generation may use this information to generate the position as non-null if field errors are handled out of band: ```graphql type User { + # email is semantically non-null and can be generated as non-null by error-handling clients. email: String @semanticNonNull } ``` -It can also be applied on object type extensions for use in client applications that do -not own the base schema: +The `levels` argument indicates what levels are semantically non null in case of lists: ```graphql -extend type User @semanticNonNull(field: "email") -``` +type User { + # friends is semantically non null + friends: [User] @semanticNonNull # same as @semanticNonNull(levels: [0]) -Control over list items is done using the `level` argument: + # every friends[k] is semantically non null + friends: [User] @semanticNonNull(levels: [1]) -```graphql -type User { - # friends is nullable but friends[0] is null only on errors - friends: [User] @semanticNonNull(level: 1) + # friends as well as every friends[k] is semantically non null + friends: [User] @semanticNonNull(levels: [0, 1]) } ``` -The `field` argument is the name of the field if `@semanticNonNull` is applied to an object definition. -If `@semanticNonNull` is applied to a field definition, `field` must be null. - -The `level` argument can be used to indicate what level is semantically non null in case of lists. -`level` starts at 0 if there is no list. If `level` is null, all levels are semantically non null. +`levels` are zero indexed. +Passing a negative level or a level greater than the list dimension is an error. """ -directive @semanticNonNull(field: String = null, level: Int = null) repeatable on FIELD_DEFINITION | OBJECT +directive @semanticNonNull(levels: [Int] = [0]) on FIELD_DEFINITION interface IPerson { name: String @metadata(argCount: 0) @semanticNonNull diff --git a/src/tests/fixtures/semantic_nullability/semanticNull.ts.expected b/src/tests/fixtures/semantic_nullability/semanticNull.ts.expected index 90ae04c1..69f782aa 100644 --- a/src/tests/fixtures/semantic_nullability/semanticNull.ts.expected +++ b/src/tests/fixtures/semantic_nullability/semanticNull.ts.expected @@ -22,42 +22,37 @@ OUTPUT ----------------- -- SDL -- """ -Indicates that a field is only null if there is a matching error in the `errors` array. -In all other cases, the field is non-null. +Indicates that a position is semantically non null: it is only null if there is a matching error in the `errors` array. +In all other cases, the position is non-null. -Tools doing code generation may use this information to generate the field as non-null. - -This directive can be applied on field definitions: +Tools doing code generation may use this information to generate the position as non-null if field errors are handled out of band: ```graphql type User { + # email is semantically non-null and can be generated as non-null by error-handling clients. email: String @semanticNonNull } ``` -It can also be applied on object type extensions for use in client applications that do -not own the base schema: +The `levels` argument indicates what levels are semantically non null in case of lists: ```graphql -extend type User @semanticNonNull(field: "email") -``` +type User { + # friends is semantically non null + friends: [User] @semanticNonNull # same as @semanticNonNull(levels: [0]) -Control over list items is done using the `level` argument: + # every friends[k] is semantically non null + friends: [User] @semanticNonNull(levels: [1]) -```graphql -type User { - # friends is nullable but friends[0] is null only on errors - friends: [User] @semanticNonNull(level: 1) + # friends as well as every friends[k] is semantically non null + friends: [User] @semanticNonNull(levels: [0, 1]) } ``` -The `field` argument is the name of the field if `@semanticNonNull` is applied to an object definition. -If `@semanticNonNull` is applied to a field definition, `field` must be null. - -The `level` argument can be used to indicate what level is semantically non null in case of lists. -`level` starts at 0 if there is no list. If `level` is null, all levels are semantically non null. +`levels` are zero indexed. +Passing a negative level or a level greater than the list dimension is an error. """ -directive @semanticNonNull(field: String = null, level: Int = null) repeatable on FIELD_DEFINITION | OBJECT +directive @semanticNonNull(levels: [Int] = [0]) on FIELD_DEFINITION type User { name: String @metadata(argCount: 0)