diff --git a/alias/language/__tests__/printer.test.js b/alias/language/__tests__/printer.test.js index 6e4d045..c24ea2b 100644 --- a/alias/language/__tests__/printer.test.js +++ b/alias/language/__tests__/printer.test.js @@ -54,6 +54,14 @@ describe('Printer: Query document', () => { name } `); + + const queryWithNullabilityFields = parse('query { id?, name! }'); + expect(print(queryWithNullabilityFields)).toBe(dedent` + { + id? + name! + } + `); }); it('prints query with variable directives', () => { diff --git a/alias/language/parser.mjs b/alias/language/parser.mjs index bb07ff3..0ccac7e 100644 --- a/alias/language/parser.mjs +++ b/alias/language/parser.mjs @@ -147,12 +147,20 @@ const directives = match()` ${directive}* `; +const nullability = match(null, (x) => { + return x[0] === '?' ? 'optional' : 'required'; +})` + :${ignored}? + ${/[?!]/} +`; + const field = match(Kind.FIELD, (x) => { let i = 0; return { kind: x.tag, alias: x[1].kind === Kind.NAME ? x[i++] : undefined, name: x[i++], + required: typeof x[i] === 'string' ? x[i++] : 'unset', arguments: x[i++], directives: x[i++], selectionSet: x[i++], @@ -164,6 +172,7 @@ const field = match(Kind.FIELD, (x) => { (?: ${ignored}? ${':'} ${ignored}?) ${name} )? + ${nullability}? ${args} ${directives} ${() => selectionSet}? diff --git a/alias/language/printer.mjs b/alias/language/printer.mjs index 74b1dc5..adf153b 100644 --- a/alias/language/printer.mjs +++ b/alias/language/printer.mjs @@ -36,11 +36,15 @@ export function print(node) { ); case 'Field': + let prefix = wrap('', print(node.alias), ': ') + print(node.name); + if (node.required === 'optional') { + prefix += '?'; + } else if (node.required === 'required') { + prefix += '!'; + } return join( [ - wrap('', print(node.alias), ': ') + - print(node.name) + - wrap('(', join(print(node.arguments), ', '), ')'), + prefix + wrap('(', join(print(node.arguments), ', '), ')'), join(print(node.directives), ' '), print(node.selectionSet), ],