Mirror: The small sibling of the graphql package, slimmed down for client-side libraries.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add tests for printer

+246 -12
+8 -8
alias/language/__tests__/parser.js
··· 47 47 }); 48 48 49 49 it('parses kitchen sink', () => { 50 - expect(() => parse(kitchenSinkQuery)).not.toThrow(); 50 + let query; 51 + expect(() => { 52 + return (query = parse(kitchenSinkQuery)); 53 + }).not.toThrow(); 54 + 55 + expect(query.definitions.length).toBe(6); 51 56 }); 52 57 53 58 it('parses anonymous mutation operations', () => { ··· 373 378 }); 374 379 }); 375 380 376 - const kitchenSinkQuery: string = String.raw` 381 + const kitchenSinkQuery = String.raw` 377 382 query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery { 378 383 whoever123is: node(id: [123, 456]) { 379 384 id ··· 420 425 foo( 421 426 size: $size 422 427 bar: $b 423 - obj: { 424 - key: "value" 425 - block: """ 426 - block string uses \""" 427 - """ 428 - } 428 + obj: { key: "value" } 429 429 ) 430 430 } 431 431 {
+236
alias/language/__tests__/printer.js
··· 1 + // See: https://github.com/graphql/graphql-js/blob/976d64b/src/language/__tests__/printer-test.ts 2 + 3 + import { parse } from '../parser'; 4 + import { print } from '../printer'; 5 + 6 + describe('Printer: Query document', () => { 7 + it('prints minimal ast', () => { 8 + const ast = { 9 + kind: 'Field', 10 + name: { kind: 'Name', value: 'foo' }, 11 + }; 12 + expect(print(ast)).toBe('foo'); 13 + }); 14 + 15 + // NOTE: The shim won't throw for invalid AST nodes 16 + it('returns empty strings for invalid AST', () => { 17 + const badAST = { random: 'Data' }; 18 + expect(print(badAST)).toBe(''); 19 + }); 20 + 21 + it('correctly prints non-query operations without name', () => { 22 + const queryASTShorthanded = parse('query { id, name }'); 23 + expect(print(queryASTShorthanded)).toBe(dedent` 24 + { 25 + id 26 + name 27 + } 28 + `); 29 + 30 + const mutationAST = parse('mutation { id, name }'); 31 + expect(print(mutationAST)).toBe(dedent` 32 + mutation { 33 + id 34 + name 35 + } 36 + `); 37 + 38 + const queryASTWithArtifacts = parse( 39 + 'query ($foo: TestType) @testDirective { id, name }' 40 + ); 41 + expect(print(queryASTWithArtifacts)).toBe(dedent` 42 + query ($foo: TestType) @testDirective { 43 + id 44 + name 45 + } 46 + `); 47 + 48 + const mutationASTWithArtifacts = parse( 49 + 'mutation ($foo: TestType) @testDirective { id, name }' 50 + ); 51 + expect(print(mutationASTWithArtifacts)).toBe(dedent` 52 + mutation ($foo: TestType) @testDirective { 53 + id 54 + name 55 + } 56 + `); 57 + }); 58 + 59 + it('prints query with variable directives', () => { 60 + const queryASTWithVariableDirective = parse( 61 + 'query ($foo: TestType = {a: 123} @testDirective(if: true) @test) { id }' 62 + ); 63 + expect(print(queryASTWithVariableDirective)).toBe(dedent` 64 + query ($foo: TestType = {a: 123} @testDirective(if: true) @test) { 65 + id 66 + } 67 + `); 68 + }); 69 + 70 + it('keeps arguments on one line if line is short (<= 80 chars)', () => { 71 + const printed = print( 72 + parse('{trip(wheelchair:false arriveBy:false){dateTime}}') 73 + ); 74 + 75 + expect(printed).toBe( 76 + dedent` 77 + { 78 + trip(wheelchair: false, arriveBy: false) { 79 + dateTime 80 + } 81 + } 82 + ` 83 + ); 84 + }); 85 + 86 + it('prints kitchen sink without altering ast', () => { 87 + const ast = parse(kitchenSinkQuery, { noLocation: true }); 88 + 89 + const astBeforePrintCall = JSON.stringify(ast); 90 + const printed = print(ast); 91 + const printedAST = parse(printed, { noLocation: true }); 92 + 93 + expect(printedAST).toEqual(ast); 94 + expect(JSON.stringify(ast)).toBe(astBeforePrintCall); 95 + 96 + expect(printed).toBe( 97 + dedentString(String.raw` 98 + query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery { 99 + whoever123is: node(id: [123, 456]) { 100 + id 101 + ... on User @onInlineFragment { 102 + field2 { 103 + id 104 + alias: field1(first: 10, after: $foo) @include(if: $foo) { 105 + id 106 + ...frag @onFragmentSpread 107 + } 108 + } 109 + } 110 + ... @skip(unless: $foo) { 111 + id 112 + } 113 + ... { 114 + id 115 + } 116 + } 117 + } 118 + 119 + mutation likeStory @onMutation { 120 + like(story: 123) @onField { 121 + story { 122 + id @onField 123 + } 124 + } 125 + } 126 + 127 + subscription StoryLikeSubscription($input: StoryLikeSubscribeInput @onVariableDefinition) @onSubscription { 128 + storyLikeSubscribe(input: $input) { 129 + story { 130 + likers { 131 + count 132 + } 133 + likeSentence { 134 + text 135 + } 136 + } 137 + } 138 + } 139 + 140 + fragment frag on Friend @onFragmentDefinition { 141 + foo(size: $size, bar: $b, obj: {key: "value"}) 142 + } 143 + 144 + { 145 + unnamed(truthy: true, falsy: false, nullish: null) 146 + query 147 + } 148 + 149 + { 150 + __typename 151 + } 152 + `) + '\n' 153 + ); 154 + }); 155 + }); 156 + 157 + const kitchenSinkQuery = String.raw` 158 + query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery { 159 + whoever123is: node(id: [123, 456]) { 160 + id 161 + ... on User @onInlineFragment { 162 + field2 { 163 + id 164 + alias: field1(first: 10, after: $foo) @include(if: $foo) { 165 + id 166 + ...frag @onFragmentSpread 167 + } 168 + } 169 + } 170 + ... @skip(unless: $foo) { 171 + id 172 + } 173 + ... { 174 + id 175 + } 176 + } 177 + } 178 + mutation likeStory @onMutation { 179 + like(story: 123) @onField { 180 + story { 181 + id @onField 182 + } 183 + } 184 + } 185 + subscription StoryLikeSubscription( 186 + $input: StoryLikeSubscribeInput @onVariableDefinition 187 + ) 188 + @onSubscription { 189 + storyLikeSubscribe(input: $input) { 190 + story { 191 + likers { 192 + count 193 + } 194 + likeSentence { 195 + text 196 + } 197 + } 198 + } 199 + } 200 + fragment frag on Friend @onFragmentDefinition { 201 + foo( 202 + size: $size 203 + bar: $b 204 + obj: { key: "value" } 205 + ) 206 + } 207 + { 208 + unnamed(truthy: true, falsy: false, nullish: null) 209 + query 210 + } 211 + query { 212 + __typename 213 + } 214 + `; 215 + 216 + function dedentString(string) { 217 + const trimmedStr = string 218 + .replace(/^\n*/m, '') // remove leading newline 219 + .replace(/[ \t\n]*$/, ''); // remove trailing spaces and tabs 220 + // fixes indentation by removing leading spaces and tabs from each line 221 + let indent = ''; 222 + for (const char of trimmedStr) { 223 + if (char !== ' ' && char !== '\t') { 224 + break; 225 + } 226 + indent += char; 227 + } 228 + 229 + return trimmedStr.replace(RegExp('^' + indent, 'mg'), ''); // remove indent 230 + } 231 + 232 + function dedent(strings, ...values) { 233 + let str = strings[0]; 234 + for (let i = 1; i < strings.length; ++i) str += values[i - 1] + strings[i]; // interpolation 235 + return dedentString(str) + '\n'; 236 + }
+2 -4
alias/language/parser.mjs
··· 58 58 ${/[eE][+-]?\d+/}? 59 59 `; 60 60 61 - // 2.9.4: Notably, this skips checks for unicode escape sequences and escaped 62 - // quotes. This is mainly meant for client-side use, so we won't have to be strict. 61 + // 2.9.4: Notably, this skips checks for unicode escape sequences and escaped quotes. 63 62 const string = match(Kind.STRING, (x) => ({ 64 63 kind: x.tag, 65 64 value: x[0], ··· 313 312 const root = match(Kind.DOCUMENT, (x) => 314 313 x.length ? { kind: x.tag, definitions: x.slice() } : undefined 315 314 )` 316 - ${queryShorthand} 317 - | (${operationDefinition} | ${fragmentDefinition})+ 315 + (${queryShorthand} | ${operationDefinition} | ${fragmentDefinition})* 318 316 `; 319 317 320 318 const _parse = makeParser(root);