ether-code 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/cli/ether.js +1 -1
  2. package/generators/css-generator.js +42 -55
  3. package/generators/graphql-generator.js +19 -22
  4. package/generators/html-generator.js +51 -220
  5. package/generators/js-generator.js +76 -157
  6. package/generators/node-generator.js +49 -93
  7. package/generators/php-generator.js +46 -68
  8. package/generators/python-generator.js +35 -54
  9. package/generators/react-generator.js +37 -47
  10. package/generators/ruby-generator.js +59 -119
  11. package/generators/sql-generator.js +42 -63
  12. package/generators/ts-generator.js +59 -133
  13. package/i18n/i18n-css.json +147 -147
  14. package/i18n/i18n-graphql.json +6 -6
  15. package/i18n/i18n-html.json +135 -135
  16. package/i18n/i18n-js.json +107 -107
  17. package/i18n/i18n-node.json +14 -14
  18. package/i18n/i18n-php.json +177 -177
  19. package/i18n/i18n-python.json +16 -16
  20. package/i18n/i18n-react.json +97 -97
  21. package/i18n/i18n-ruby.json +22 -22
  22. package/i18n/i18n-sql.json +153 -153
  23. package/i18n/i18n-ts.json +10 -10
  24. package/lexer/ether-lexer.js +175 -34
  25. package/lexer/tokens.js +6 -6
  26. package/package.json +1 -1
  27. package/parsers/ast-css.js +0 -545
  28. package/parsers/ast-graphql.js +0 -424
  29. package/parsers/ast-html.js +0 -886
  30. package/parsers/ast-js.js +0 -750
  31. package/parsers/ast-node.js +0 -2440
  32. package/parsers/ast-php.js +0 -957
  33. package/parsers/ast-react.js +0 -580
  34. package/parsers/ast-ruby.js +0 -895
  35. package/parsers/ast-ts.js +0 -1352
  36. package/parsers/css-parser.js +0 -1981
  37. package/parsers/graphql-parser.js +0 -2011
  38. package/parsers/html-parser.js +0 -1182
  39. package/parsers/js-parser.js +0 -2564
  40. package/parsers/node-parser.js +0 -2644
  41. package/parsers/php-parser.js +0 -3037
  42. package/parsers/react-parser.js +0 -1035
  43. package/parsers/ruby-parser.js +0 -2680
  44. package/parsers/ts-parser.js +0 -3881
@@ -1,2011 +0,0 @@
1
- const fs = require('fs')
2
- const path = require('path')
3
- const AST = require('./ast-graphql')
4
-
5
- class EtherGraphQLParser {
6
- constructor(i18nPath = null) {
7
- this.i18n = null
8
- this.keywordMap = {}
9
- this.reverseKeywordMap = {}
10
- this.tokens = []
11
- this.pos = 0
12
- this.indentStack = [0]
13
- this.currentIndent = 0
14
-
15
- if (i18nPath) {
16
- this.loadI18n(i18nPath)
17
- }
18
- }
19
-
20
- loadI18n(filePath) {
21
- const content = fs.readFileSync(filePath, 'utf-8')
22
- this.i18n = JSON.parse(content)
23
- this.buildKeywordMaps()
24
- }
25
-
26
- buildKeywordMaps() {
27
- if (!this.i18n) return
28
-
29
- const processSection = (section, category = null) => {
30
- for (const [key, translations] of Object.entries(section)) {
31
- if (typeof translations === 'object' && translations.fr) {
32
- const graphqlValue = translations.graphql || key
33
- for (const [lang, value] of Object.entries(translations)) {
34
- if (lang !== 'graphql' && value) {
35
- const mapKey = category ? `${category}.${value}` : value
36
- this.keywordMap[value.toLowerCase()] = {
37
- graphql: graphqlValue,
38
- category: category,
39
- key: key
40
- }
41
- if (!this.reverseKeywordMap[graphqlValue]) {
42
- this.reverseKeywordMap[graphqlValue] = {}
43
- }
44
- this.reverseKeywordMap[graphqlValue][lang] = value
45
- }
46
- }
47
- } else if (typeof translations === 'object') {
48
- processSection(translations, key)
49
- }
50
- }
51
- }
52
-
53
- processSection(this.i18n.operations)
54
- processSection(this.i18n.typeDefinitions)
55
- processSection(this.i18n.keywords)
56
- processSection(this.i18n.builtInScalars)
57
- processSection(this.i18n.customScalars)
58
- processSection(this.i18n.literals)
59
- processSection(this.i18n.directives)
60
- processSection(this.i18n.directiveArguments)
61
- processSection(this.i18n.metaFields)
62
- processSection(this.i18n.introspection)
63
- processSection(this.i18n.commonFieldNames)
64
- processSection(this.i18n.paginationArgs)
65
- processSection(this.i18n.connectionTypes)
66
- }
67
-
68
- translateKeyword(word) {
69
- const lower = word.toLowerCase()
70
- if (this.keywordMap[lower]) {
71
- return this.keywordMap[lower].graphql
72
- }
73
- return word
74
- }
75
-
76
- translateType(typeName) {
77
- const typeMap = {
78
- 'texte': 'String',
79
- 'text': 'String',
80
- 'texto': 'String',
81
- 'текст': 'String',
82
- '文本': 'String',
83
- 'テキスト': 'String',
84
- 'entier': 'Int',
85
- 'integer': 'Int',
86
- 'entero': 'Int',
87
- 'целое': 'Int',
88
- '整数': 'Int',
89
- 'decimal': 'Float',
90
- 'float': 'Float',
91
- 'дробное': 'Float',
92
- '浮点': 'Float',
93
- '浮動小数点': 'Float',
94
- 'booleen': 'Boolean',
95
- 'booléen': 'Boolean',
96
- 'boolean': 'Boolean',
97
- 'booleano': 'Boolean',
98
- 'логический': 'Boolean',
99
- '布尔': 'Boolean',
100
- 'ブール': 'Boolean',
101
- 'dateheure': 'DateTime',
102
- 'datetime': 'DateTime',
103
- 'fechahora': 'DateTime',
104
- 'датавремя': 'DateTime',
105
- '日期时间': 'DateTime',
106
- '日時': 'DateTime',
107
- 'date': 'Date',
108
- 'fecha': 'Date',
109
- 'дата': 'Date',
110
- '日期': 'Date',
111
- '日付': 'Date',
112
- 'heure': 'Time',
113
- 'time': 'Time',
114
- 'hora': 'Time',
115
- 'время': 'Time',
116
- '时间': 'Time',
117
- '時刻': 'Time'
118
- }
119
- const lower = typeName.toLowerCase()
120
- return typeMap[lower] || typeName
121
- }
122
-
123
- tokenize(source) {
124
- this.tokens = []
125
- const lines = source.split('\n')
126
- let lineNum = 0
127
-
128
- for (const line of lines) {
129
- lineNum++
130
- const trimmed = line.trimEnd()
131
- if (trimmed.length === 0) continue
132
-
133
- const indent = line.length - line.trimStart().length
134
- const content = line.trimStart()
135
-
136
- if (content.startsWith('#')) continue
137
-
138
- this.tokens.push({
139
- type: 'LINE',
140
- indent: indent,
141
- content: content,
142
- line: lineNum,
143
- tokens: this.tokenizeLine(content)
144
- })
145
- }
146
-
147
- return this.tokens
148
- }
149
-
150
- tokenizeLine(line) {
151
- const tokens = []
152
- let pos = 0
153
-
154
- while (pos < line.length) {
155
- if (/\s/.test(line[pos])) {
156
- pos++
157
- continue
158
- }
159
-
160
- if (line.substring(pos, pos + 3) === '...') {
161
- tokens.push({ type: 'SPREAD', value: '...' })
162
- pos += 3
163
- continue
164
- }
165
-
166
- if (line.substring(pos, pos + 3) === '"""') {
167
- const endPos = line.indexOf('"""', pos + 3)
168
- if (endPos !== -1) {
169
- tokens.push({ type: 'BLOCK_STRING', value: line.substring(pos + 3, endPos) })
170
- pos = endPos + 3
171
- } else {
172
- tokens.push({ type: 'BLOCK_STRING_START', value: line.substring(pos + 3) })
173
- pos = line.length
174
- }
175
- continue
176
- }
177
-
178
- if (line[pos] === '"' || line[pos] === "'") {
179
- const quote = line[pos]
180
- let str = ''
181
- pos++
182
- while (pos < line.length && line[pos] !== quote) {
183
- if (line[pos] === '\\' && pos + 1 < line.length) {
184
- pos++
185
- switch (line[pos]) {
186
- case 'n': str += '\n'; break
187
- case 't': str += '\t'; break
188
- case 'r': str += '\r'; break
189
- case '\\': str += '\\'; break
190
- case '"': str += '"'; break
191
- case "'": str += "'"; break
192
- default: str += line[pos]
193
- }
194
- } else {
195
- str += line[pos]
196
- }
197
- pos++
198
- }
199
- pos++
200
- tokens.push({ type: 'STRING', value: str })
201
- continue
202
- }
203
-
204
- if (line[pos] === '@') {
205
- let directive = '@'
206
- pos++
207
- while (pos < line.length && /[\w]/.test(line[pos])) {
208
- directive += line[pos]
209
- pos++
210
- }
211
- tokens.push({ type: 'DIRECTIVE', value: directive })
212
- continue
213
- }
214
-
215
- if (line[pos] === ':') {
216
- tokens.push({ type: 'COLON', value: ':' })
217
- pos++
218
- continue
219
- }
220
-
221
- if (line[pos] === '=') {
222
- tokens.push({ type: 'EQUALS', value: '=' })
223
- pos++
224
- continue
225
- }
226
-
227
- if (line[pos] === ',') {
228
- tokens.push({ type: 'COMMA', value: ',' })
229
- pos++
230
- continue
231
- }
232
-
233
- if (line[pos] === '!') {
234
- tokens.push({ type: 'BANG', value: '!' })
235
- pos++
236
- continue
237
- }
238
-
239
- if (line[pos] === '|') {
240
- tokens.push({ type: 'PIPE', value: '|' })
241
- pos++
242
- continue
243
- }
244
-
245
- if (line[pos] === '-' && line[pos + 1] === '>') {
246
- tokens.push({ type: 'ARROW', value: '->' })
247
- pos += 2
248
- continue
249
- }
250
-
251
- if (/[-]?\d/.test(line[pos])) {
252
- let num = ''
253
- if (line[pos] === '-') {
254
- num = '-'
255
- pos++
256
- }
257
- while (pos < line.length && /[\d.]/.test(line[pos])) {
258
- num += line[pos]
259
- pos++
260
- }
261
- if (num.includes('.')) {
262
- tokens.push({ type: 'FLOAT', value: parseFloat(num) })
263
- } else {
264
- tokens.push({ type: 'INT', value: parseInt(num, 10) })
265
- }
266
- continue
267
- }
268
-
269
- if (/[\w_\u00C0-\u024F\u0400-\u04FF\u4E00-\u9FFF\u3040-\u30FF]/.test(line[pos])) {
270
- let ident = ''
271
- while (pos < line.length && /[\w_\u00C0-\u024F\u0400-\u04FF\u4E00-\u9FFF\u3040-\u30FF]/.test(line[pos])) {
272
- ident += line[pos]
273
- pos++
274
- }
275
- tokens.push({ type: 'IDENTIFIER', value: ident })
276
- continue
277
- }
278
-
279
- pos++
280
- }
281
-
282
- return tokens
283
- }
284
-
285
- parse(source) {
286
- this.tokenize(source)
287
- this.pos = 0
288
- const definitions = []
289
-
290
- while (this.pos < this.tokens.length) {
291
- const def = this.parseDefinition()
292
- if (def) {
293
- definitions.push(def)
294
- }
295
- }
296
-
297
- return new AST.DocumentNode(definitions)
298
- }
299
-
300
- currentLine() {
301
- return this.tokens[this.pos] || null
302
- }
303
-
304
- advance() {
305
- this.pos++
306
- }
307
-
308
- parseDefinition() {
309
- const line = this.currentLine()
310
- if (!line) return null
311
-
312
- const firstToken = line.tokens[0]
313
- if (!firstToken) {
314
- this.advance()
315
- return null
316
- }
317
-
318
- const keyword = this.translateKeyword(firstToken.value)
319
-
320
- switch (keyword) {
321
- case 'query':
322
- case 'mutation':
323
- case 'subscription':
324
- return this.parseOperationDefinition(keyword)
325
- case 'fragment':
326
- return this.parseFragmentDefinition()
327
- case 'type':
328
- return this.parseObjectTypeDefinition()
329
- case 'input':
330
- return this.parseInputObjectTypeDefinition()
331
- case 'interface':
332
- return this.parseInterfaceTypeDefinition()
333
- case 'union':
334
- return this.parseUnionTypeDefinition()
335
- case 'enum':
336
- return this.parseEnumTypeDefinition()
337
- case 'scalar':
338
- return this.parseScalarTypeDefinition()
339
- case 'schema':
340
- return this.parseSchemaDefinition()
341
- case 'directive':
342
- return this.parseDirectiveDefinition()
343
- case 'extend':
344
- return this.parseTypeExtension()
345
- default:
346
- if (firstToken.type === 'STRING' || firstToken.type === 'BLOCK_STRING') {
347
- return this.parseDefinitionWithDescription()
348
- }
349
- this.advance()
350
- return null
351
- }
352
- }
353
-
354
- parseDefinitionWithDescription() {
355
- const line = this.currentLine()
356
- const descToken = line.tokens[0]
357
- const description = new AST.StringValueNode(
358
- descToken.value,
359
- descToken.type === 'BLOCK_STRING'
360
- )
361
- this.advance()
362
-
363
- const def = this.parseDefinition()
364
- if (def) {
365
- def.description = description
366
- }
367
- return def
368
- }
369
-
370
- parseOperationDefinition(operation) {
371
- const line = this.currentLine()
372
- const baseIndent = line.indent
373
- let name = null
374
- let variableDefinitions = []
375
- let directives = []
376
- let tokenIdx = 1
377
-
378
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
379
- const nextToken = line.tokens[tokenIdx + 1]
380
- if (!nextToken || nextToken.type !== 'COLON' ||
381
- (line.tokens[tokenIdx + 2] && this.translateKeyword(line.tokens[tokenIdx].value) !== 'with')) {
382
- name = new AST.NameNode(line.tokens[tokenIdx].value)
383
- tokenIdx++
384
- }
385
- }
386
-
387
- if (line.tokens[tokenIdx] && this.translateKeyword(line.tokens[tokenIdx].value) === 'with') {
388
- tokenIdx++
389
- variableDefinitions = this.parseVariableDefinitionsInline(line.tokens, tokenIdx)
390
- }
391
-
392
- for (let i = tokenIdx; i < line.tokens.length; i++) {
393
- if (line.tokens[i].type === 'DIRECTIVE') {
394
- directives.push(this.parseDirectiveInline(line.tokens, i))
395
- }
396
- }
397
-
398
- this.advance()
399
- const selectionSet = this.parseSelectionSet(baseIndent)
400
-
401
- return new AST.OperationDefinitionNode(
402
- operation,
403
- name,
404
- variableDefinitions,
405
- directives,
406
- selectionSet
407
- )
408
- }
409
-
410
- parseVariableDefinitionsInline(tokens, startIdx) {
411
- const definitions = []
412
- let idx = startIdx
413
-
414
- while (idx < tokens.length) {
415
- if (tokens[idx].type === 'DIRECTIVE') break
416
-
417
- if (tokens[idx].type === 'IDENTIFIER') {
418
- const varName = new AST.NameNode(tokens[idx].value)
419
- idx++
420
-
421
- if (tokens[idx] && tokens[idx].type === 'COLON') {
422
- idx++
423
- }
424
-
425
- let type = null
426
- let defaultValue = null
427
-
428
- if (tokens[idx]) {
429
- const typeResult = this.parseTypeInline(tokens, idx)
430
- type = typeResult.type
431
- idx = typeResult.nextIdx
432
- }
433
-
434
- if (tokens[idx] && tokens[idx].type === 'EQUALS') {
435
- idx++
436
- const valueResult = this.parseValueInline(tokens, idx)
437
- defaultValue = valueResult.value
438
- idx = valueResult.nextIdx
439
- }
440
-
441
- definitions.push(new AST.VariableDefinitionNode(
442
- new AST.VariableNode(varName),
443
- type,
444
- defaultValue,
445
- []
446
- ))
447
- }
448
-
449
- if (tokens[idx] && tokens[idx].type === 'COMMA') {
450
- idx++
451
- } else {
452
- break
453
- }
454
- }
455
-
456
- return definitions
457
- }
458
-
459
- parseTypeInline(tokens, startIdx) {
460
- let idx = startIdx
461
- let isListNonNull = false
462
- let isItemNonNull = false
463
- let isList = false
464
- let typeName = null
465
-
466
- if (tokens[idx] && this.translateKeyword(tokens[idx].value) === '[]') {
467
- isList = true
468
- idx++
469
- }
470
-
471
- const listKeyword = tokens[idx] ? this.translateKeyword(tokens[idx].value) : null
472
- if (listKeyword === 'list' || listKeyword === '[]') {
473
- isList = true
474
- idx++
475
- if (tokens[idx] && tokens[idx].type === 'BANG') {
476
- isListNonNull = true
477
- idx++
478
- }
479
- }
480
-
481
- if (tokens[idx] && tokens[idx].type === 'IDENTIFIER') {
482
- typeName = this.translateType(tokens[idx].value)
483
- idx++
484
- }
485
-
486
- if (tokens[idx] && tokens[idx].type === 'BANG') {
487
- isItemNonNull = true
488
- idx++
489
- }
490
-
491
- let type = new AST.NamedTypeNode(new AST.NameNode(typeName))
492
-
493
- if (isItemNonNull) {
494
- type = new AST.NonNullTypeNode(type)
495
- }
496
-
497
- if (isList) {
498
- type = new AST.ListTypeNode(type)
499
- if (isListNonNull) {
500
- type = new AST.NonNullTypeNode(type)
501
- }
502
- }
503
-
504
- return { type, nextIdx: idx }
505
- }
506
-
507
- parseValueInline(tokens, startIdx) {
508
- let idx = startIdx
509
- const token = tokens[idx]
510
-
511
- if (!token) {
512
- return { value: null, nextIdx: idx }
513
- }
514
-
515
- if (token.type === 'STRING') {
516
- return { value: new AST.StringValueNode(token.value), nextIdx: idx + 1 }
517
- }
518
-
519
- if (token.type === 'INT') {
520
- return { value: new AST.IntValueNode(token.value), nextIdx: idx + 1 }
521
- }
522
-
523
- if (token.type === 'FLOAT') {
524
- return { value: new AST.FloatValueNode(token.value), nextIdx: idx + 1 }
525
- }
526
-
527
- if (token.type === 'IDENTIFIER') {
528
- const translated = this.translateKeyword(token.value)
529
- if (translated === 'true') {
530
- return { value: new AST.BooleanValueNode(true), nextIdx: idx + 1 }
531
- }
532
- if (translated === 'false') {
533
- return { value: new AST.BooleanValueNode(false), nextIdx: idx + 1 }
534
- }
535
- if (translated === 'null') {
536
- return { value: new AST.NullValueNode(), nextIdx: idx + 1 }
537
- }
538
- return { value: new AST.EnumValueNode(token.value), nextIdx: idx + 1 }
539
- }
540
-
541
- return { value: null, nextIdx: idx + 1 }
542
- }
543
-
544
- parseDirectiveInline(tokens, startIdx) {
545
- const directiveToken = tokens[startIdx]
546
- const name = new AST.NameNode(this.translateKeyword(directiveToken.value.substring(1)))
547
- const args = []
548
- let idx = startIdx + 1
549
-
550
- if (tokens[idx] && tokens[idx].type === 'COLON') {
551
- idx++
552
- while (idx < tokens.length) {
553
- if (tokens[idx].type === 'DIRECTIVE') break
554
-
555
- if (tokens[idx].type === 'IDENTIFIER') {
556
- const argName = new AST.NameNode(this.translateKeyword(tokens[idx].value))
557
- idx++
558
-
559
- if (tokens[idx] && tokens[idx].type === 'EQUALS') {
560
- idx++
561
- const valueResult = this.parseValueInline(tokens, idx)
562
- args.push(new AST.ArgumentNode(argName, valueResult.value))
563
- idx = valueResult.nextIdx
564
- }
565
- }
566
-
567
- if (tokens[idx] && tokens[idx].type === 'COMMA') {
568
- idx++
569
- } else {
570
- break
571
- }
572
- }
573
- }
574
-
575
- return new AST.DirectiveNode(name, args)
576
- }
577
-
578
- parseSelectionSet(parentIndent) {
579
- const selections = []
580
-
581
- while (this.pos < this.tokens.length) {
582
- const line = this.currentLine()
583
- if (!line || line.indent <= parentIndent) break
584
-
585
- const selection = this.parseSelection(line)
586
- if (selection) {
587
- selections.push(selection)
588
- }
589
- }
590
-
591
- return new AST.SelectionSetNode(selections)
592
- }
593
-
594
- parseSelection(line) {
595
- const firstToken = line.tokens[0]
596
- if (!firstToken) {
597
- this.advance()
598
- return null
599
- }
600
-
601
- if (firstToken.type === 'SPREAD') {
602
- return this.parseFragmentSpreadOrInline(line)
603
- }
604
-
605
- return this.parseField(line)
606
- }
607
-
608
- parseFragmentSpreadOrInline(line) {
609
- const baseIndent = line.indent
610
- let tokenIdx = 1
611
-
612
- if (line.tokens[tokenIdx] && this.translateKeyword(line.tokens[tokenIdx].value) === 'on') {
613
- tokenIdx++
614
- const typeName = new AST.NameNode(line.tokens[tokenIdx].value)
615
- const typeCondition = new AST.NamedTypeNode(typeName)
616
- tokenIdx++
617
-
618
- const directives = []
619
- for (let i = tokenIdx; i < line.tokens.length; i++) {
620
- if (line.tokens[i].type === 'DIRECTIVE') {
621
- directives.push(this.parseDirectiveInline(line.tokens, i))
622
- }
623
- }
624
-
625
- this.advance()
626
- const selectionSet = this.parseSelectionSet(baseIndent)
627
-
628
- return new AST.InlineFragmentNode(typeCondition, directives, selectionSet)
629
- }
630
-
631
- const fragmentName = new AST.NameNode(line.tokens[tokenIdx].value)
632
- tokenIdx++
633
-
634
- const directives = []
635
- for (let i = tokenIdx; i < line.tokens.length; i++) {
636
- if (line.tokens[i].type === 'DIRECTIVE') {
637
- directives.push(this.parseDirectiveInline(line.tokens, i))
638
- }
639
- }
640
-
641
- this.advance()
642
- return new AST.FragmentSpreadNode(fragmentName, directives)
643
- }
644
-
645
- parseField(line) {
646
- const baseIndent = line.indent
647
- let alias = null
648
- let name = null
649
- let args = []
650
- let directives = []
651
- let tokenIdx = 0
652
-
653
- const firstIdent = line.tokens[tokenIdx]
654
- if (firstIdent && firstIdent.type === 'IDENTIFIER') {
655
- if (line.tokens[tokenIdx + 1] && line.tokens[tokenIdx + 1].type === 'COLON') {
656
- if (line.tokens[tokenIdx + 2] && line.tokens[tokenIdx + 2].type === 'IDENTIFIER') {
657
- const nextNext = line.tokens[tokenIdx + 3]
658
- if (!nextNext || nextNext.type === 'COLON' || nextNext.type === 'DIRECTIVE') {
659
- alias = new AST.NameNode(firstIdent.value)
660
- tokenIdx += 2
661
- name = new AST.NameNode(this.translateKeyword(line.tokens[tokenIdx].value))
662
- tokenIdx++
663
- } else {
664
- name = new AST.NameNode(this.translateKeyword(firstIdent.value))
665
- tokenIdx++
666
- }
667
- } else {
668
- name = new AST.NameNode(this.translateKeyword(firstIdent.value))
669
- tokenIdx++
670
- }
671
- } else {
672
- name = new AST.NameNode(this.translateKeyword(firstIdent.value))
673
- tokenIdx++
674
- }
675
- }
676
-
677
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'COLON') {
678
- tokenIdx++
679
- args = this.parseArgumentsInline(line.tokens, tokenIdx)
680
- tokenIdx = this.findNextDirectiveOrEnd(line.tokens, tokenIdx)
681
- }
682
-
683
- for (let i = tokenIdx; i < line.tokens.length; i++) {
684
- if (line.tokens[i].type === 'DIRECTIVE') {
685
- directives.push(this.parseDirectiveInline(line.tokens, i))
686
- }
687
- }
688
-
689
- this.advance()
690
-
691
- let selectionSet = null
692
- if (this.pos < this.tokens.length && this.currentLine().indent > baseIndent) {
693
- selectionSet = this.parseSelectionSet(baseIndent)
694
- }
695
-
696
- return new AST.FieldNode(alias, name, args, directives, selectionSet)
697
- }
698
-
699
- parseArgumentsInline(tokens, startIdx) {
700
- const args = []
701
- let idx = startIdx
702
-
703
- while (idx < tokens.length) {
704
- if (tokens[idx].type === 'DIRECTIVE') break
705
-
706
- if (tokens[idx].type === 'IDENTIFIER') {
707
- const argName = new AST.NameNode(this.translateKeyword(tokens[idx].value))
708
- idx++
709
-
710
- if (tokens[idx] && tokens[idx].type === 'EQUALS') {
711
- idx++
712
- const valueResult = this.parseArgumentValue(tokens, idx)
713
- args.push(new AST.ArgumentNode(argName, valueResult.value))
714
- idx = valueResult.nextIdx
715
- }
716
- }
717
-
718
- if (tokens[idx] && tokens[idx].type === 'COMMA') {
719
- idx++
720
- } else if (tokens[idx] && tokens[idx].type !== 'IDENTIFIER') {
721
- break
722
- }
723
- }
724
-
725
- return args
726
- }
727
-
728
- parseArgumentValue(tokens, startIdx) {
729
- let idx = startIdx
730
- const token = tokens[idx]
731
-
732
- if (!token) {
733
- return { value: null, nextIdx: idx }
734
- }
735
-
736
- if (token.type === 'STRING') {
737
- return { value: new AST.StringValueNode(token.value), nextIdx: idx + 1 }
738
- }
739
-
740
- if (token.type === 'INT') {
741
- return { value: new AST.IntValueNode(token.value), nextIdx: idx + 1 }
742
- }
743
-
744
- if (token.type === 'FLOAT') {
745
- return { value: new AST.FloatValueNode(token.value), nextIdx: idx + 1 }
746
- }
747
-
748
- if (token.type === 'IDENTIFIER') {
749
- const translated = this.translateKeyword(token.value)
750
- if (translated === 'true') {
751
- return { value: new AST.BooleanValueNode(true), nextIdx: idx + 1 }
752
- }
753
- if (translated === 'false') {
754
- return { value: new AST.BooleanValueNode(false), nextIdx: idx + 1 }
755
- }
756
- if (translated === 'null') {
757
- return { value: new AST.NullValueNode(), nextIdx: idx + 1 }
758
- }
759
-
760
- if (tokens[idx + 1] && tokens[idx + 1].type === 'COLON') {
761
- return this.parseObjectValueInline(tokens, idx)
762
- }
763
-
764
- return { value: new AST.VariableNode(new AST.NameNode(token.value)), nextIdx: idx + 1 }
765
- }
766
-
767
- return { value: null, nextIdx: idx + 1 }
768
- }
769
-
770
- parseObjectValueInline(tokens, startIdx) {
771
- const fields = []
772
- let idx = startIdx
773
-
774
- while (idx < tokens.length) {
775
- if (tokens[idx].type === 'DIRECTIVE') break
776
- if (tokens[idx].type === 'COMMA' && tokens[idx + 1] &&
777
- tokens[idx + 1].type === 'IDENTIFIER' &&
778
- tokens[idx + 2] && tokens[idx + 2].type === 'EQUALS') {
779
- break
780
- }
781
-
782
- if (tokens[idx].type === 'IDENTIFIER') {
783
- const fieldName = new AST.NameNode(tokens[idx].value)
784
- idx++
785
-
786
- if (tokens[idx] && tokens[idx].type === 'COLON') {
787
- idx++
788
- const valueResult = this.parseValueInline(tokens, idx)
789
- fields.push(new AST.ObjectFieldNode(fieldName, valueResult.value))
790
- idx = valueResult.nextIdx
791
- }
792
- }
793
-
794
- if (tokens[idx] && tokens[idx].type === 'COMMA') {
795
- if (tokens[idx + 1] && tokens[idx + 1].type === 'IDENTIFIER' &&
796
- tokens[idx + 2] && tokens[idx + 2].type === 'EQUALS') {
797
- break
798
- }
799
- idx++
800
- } else {
801
- break
802
- }
803
- }
804
-
805
- return { value: new AST.ObjectValueNode(fields), nextIdx: idx }
806
- }
807
-
808
- findNextDirectiveOrEnd(tokens, startIdx) {
809
- for (let i = startIdx; i < tokens.length; i++) {
810
- if (tokens[i].type === 'DIRECTIVE') return i
811
- }
812
- return tokens.length
813
- }
814
-
815
- parseFragmentDefinition() {
816
- const line = this.currentLine()
817
- const baseIndent = line.indent
818
- let name = null
819
- let typeCondition = null
820
- let directives = []
821
- let tokenIdx = 1
822
-
823
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
824
- name = new AST.NameNode(line.tokens[tokenIdx].value)
825
- tokenIdx++
826
- }
827
-
828
- if (line.tokens[tokenIdx] && this.translateKeyword(line.tokens[tokenIdx].value) === 'on') {
829
- tokenIdx++
830
- if (line.tokens[tokenIdx]) {
831
- typeCondition = new AST.NamedTypeNode(new AST.NameNode(line.tokens[tokenIdx].value))
832
- tokenIdx++
833
- }
834
- }
835
-
836
- for (let i = tokenIdx; i < line.tokens.length; i++) {
837
- if (line.tokens[i].type === 'DIRECTIVE') {
838
- directives.push(this.parseDirectiveInline(line.tokens, i))
839
- }
840
- }
841
-
842
- this.advance()
843
- const selectionSet = this.parseSelectionSet(baseIndent)
844
-
845
- return new AST.FragmentDefinitionNode(name, typeCondition, directives, selectionSet)
846
- }
847
-
848
- parseObjectTypeDefinition() {
849
- const line = this.currentLine()
850
- const baseIndent = line.indent
851
- let name = null
852
- let interfaces = []
853
- let directives = []
854
- let tokenIdx = 1
855
-
856
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
857
- name = new AST.NameNode(line.tokens[tokenIdx].value)
858
- tokenIdx++
859
- }
860
-
861
- if (line.tokens[tokenIdx] && this.translateKeyword(line.tokens[tokenIdx].value) === 'implements') {
862
- tokenIdx++
863
- while (tokenIdx < line.tokens.length) {
864
- if (line.tokens[tokenIdx].type === 'DIRECTIVE') break
865
- if (line.tokens[tokenIdx].type === 'IDENTIFIER') {
866
- interfaces.push(new AST.NamedTypeNode(new AST.NameNode(line.tokens[tokenIdx].value)))
867
- tokenIdx++
868
- }
869
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'COMMA') {
870
- tokenIdx++
871
- } else {
872
- break
873
- }
874
- }
875
- }
876
-
877
- for (let i = tokenIdx; i < line.tokens.length; i++) {
878
- if (line.tokens[i].type === 'DIRECTIVE') {
879
- directives.push(this.parseDirectiveInline(line.tokens, i))
880
- }
881
- }
882
-
883
- this.advance()
884
- const fields = this.parseFieldDefinitions(baseIndent)
885
-
886
- return new AST.ObjectTypeDefinitionNode(null, name, interfaces, directives, fields)
887
- }
888
-
889
- parseFieldDefinitions(parentIndent) {
890
- const fields = []
891
-
892
- while (this.pos < this.tokens.length) {
893
- const line = this.currentLine()
894
- if (!line || line.indent <= parentIndent) break
895
-
896
- const field = this.parseFieldDefinition(line)
897
- if (field) {
898
- fields.push(field)
899
- }
900
- }
901
-
902
- return fields
903
- }
904
-
905
- parseFieldDefinition(line) {
906
- let name = null
907
- let args = []
908
- let type = null
909
- let directives = []
910
- let tokenIdx = 0
911
- let description = null
912
-
913
- if (line.tokens[0] && (line.tokens[0].type === 'STRING' || line.tokens[0].type === 'BLOCK_STRING')) {
914
- description = new AST.StringValueNode(line.tokens[0].value, line.tokens[0].type === 'BLOCK_STRING')
915
- tokenIdx++
916
- }
917
-
918
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
919
- name = new AST.NameNode(this.translateKeyword(line.tokens[tokenIdx].value))
920
- tokenIdx++
921
- }
922
-
923
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'COLON') {
924
- tokenIdx++
925
-
926
- while (tokenIdx < line.tokens.length) {
927
- if (line.tokens[tokenIdx].type === 'ARROW') break
928
- if (line.tokens[tokenIdx].type === 'DIRECTIVE') break
929
-
930
- if (line.tokens[tokenIdx].type === 'IDENTIFIER') {
931
- const nextToken = line.tokens[tokenIdx + 1]
932
- if (nextToken && nextToken.type === 'EQUALS') {
933
- const argName = new AST.NameNode(this.translateKeyword(line.tokens[tokenIdx].value))
934
- tokenIdx += 2
935
-
936
- const typeResult = this.parseTypeInline(line.tokens, tokenIdx)
937
- let defaultValue = null
938
- tokenIdx = typeResult.nextIdx
939
-
940
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'EQUALS') {
941
- tokenIdx++
942
- const valueResult = this.parseValueInline(line.tokens, tokenIdx)
943
- defaultValue = valueResult.value
944
- tokenIdx = valueResult.nextIdx
945
- }
946
-
947
- args.push(new AST.InputValueDefinitionNode(null, argName, typeResult.type, defaultValue, []))
948
- } else {
949
- break
950
- }
951
- }
952
-
953
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'COMMA') {
954
- tokenIdx++
955
- } else {
956
- break
957
- }
958
- }
959
- }
960
-
961
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'ARROW') {
962
- tokenIdx++
963
- }
964
-
965
- if (line.tokens[tokenIdx]) {
966
- const typeResult = this.parseTypeInline(line.tokens, tokenIdx)
967
- type = typeResult.type
968
- tokenIdx = typeResult.nextIdx
969
- }
970
-
971
- for (let i = tokenIdx; i < line.tokens.length; i++) {
972
- if (line.tokens[i].type === 'DIRECTIVE') {
973
- directives.push(this.parseDirectiveInline(line.tokens, i))
974
- }
975
- }
976
-
977
- this.advance()
978
-
979
- return new AST.FieldDefinitionNode(description, name, args, type, directives)
980
- }
981
-
982
- parseInputObjectTypeDefinition() {
983
- const line = this.currentLine()
984
- const baseIndent = line.indent
985
- let name = null
986
- let directives = []
987
- let tokenIdx = 1
988
-
989
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
990
- name = new AST.NameNode(line.tokens[tokenIdx].value)
991
- tokenIdx++
992
- }
993
-
994
- for (let i = tokenIdx; i < line.tokens.length; i++) {
995
- if (line.tokens[i].type === 'DIRECTIVE') {
996
- directives.push(this.parseDirectiveInline(line.tokens, i))
997
- }
998
- }
999
-
1000
- this.advance()
1001
- const fields = this.parseInputFieldDefinitions(baseIndent)
1002
-
1003
- return new AST.InputObjectTypeDefinitionNode(null, name, directives, fields)
1004
- }
1005
-
1006
- parseInputFieldDefinitions(parentIndent) {
1007
- const fields = []
1008
-
1009
- while (this.pos < this.tokens.length) {
1010
- const line = this.currentLine()
1011
- if (!line || line.indent <= parentIndent) break
1012
-
1013
- const field = this.parseInputFieldDefinition(line)
1014
- if (field) {
1015
- fields.push(field)
1016
- }
1017
- }
1018
-
1019
- return fields
1020
- }
1021
-
1022
- parseInputFieldDefinition(line) {
1023
- let name = null
1024
- let type = null
1025
- let defaultValue = null
1026
- let directives = []
1027
- let tokenIdx = 0
1028
- let description = null
1029
-
1030
- if (line.tokens[0] && (line.tokens[0].type === 'STRING' || line.tokens[0].type === 'BLOCK_STRING')) {
1031
- description = new AST.StringValueNode(line.tokens[0].value, line.tokens[0].type === 'BLOCK_STRING')
1032
- tokenIdx++
1033
- }
1034
-
1035
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
1036
- name = new AST.NameNode(this.translateKeyword(line.tokens[tokenIdx].value))
1037
- tokenIdx++
1038
- }
1039
-
1040
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'COLON') {
1041
- tokenIdx++
1042
- const typeResult = this.parseTypeInline(line.tokens, tokenIdx)
1043
- type = typeResult.type
1044
- tokenIdx = typeResult.nextIdx
1045
- }
1046
-
1047
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'EQUALS') {
1048
- tokenIdx++
1049
- const valueResult = this.parseValueInline(line.tokens, tokenIdx)
1050
- defaultValue = valueResult.value
1051
- tokenIdx = valueResult.nextIdx
1052
- }
1053
-
1054
- for (let i = tokenIdx; i < line.tokens.length; i++) {
1055
- if (line.tokens[i].type === 'DIRECTIVE') {
1056
- directives.push(this.parseDirectiveInline(line.tokens, i))
1057
- }
1058
- }
1059
-
1060
- this.advance()
1061
-
1062
- return new AST.InputValueDefinitionNode(description, name, type, defaultValue, directives)
1063
- }
1064
-
1065
- parseInterfaceTypeDefinition() {
1066
- const line = this.currentLine()
1067
- const baseIndent = line.indent
1068
- let name = null
1069
- let interfaces = []
1070
- let directives = []
1071
- let tokenIdx = 1
1072
-
1073
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
1074
- name = new AST.NameNode(line.tokens[tokenIdx].value)
1075
- tokenIdx++
1076
- }
1077
-
1078
- if (line.tokens[tokenIdx] && this.translateKeyword(line.tokens[tokenIdx].value) === 'implements') {
1079
- tokenIdx++
1080
- while (tokenIdx < line.tokens.length) {
1081
- if (line.tokens[tokenIdx].type === 'DIRECTIVE') break
1082
- if (line.tokens[tokenIdx].type === 'IDENTIFIER') {
1083
- interfaces.push(new AST.NamedTypeNode(new AST.NameNode(line.tokens[tokenIdx].value)))
1084
- tokenIdx++
1085
- }
1086
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'COMMA') {
1087
- tokenIdx++
1088
- } else {
1089
- break
1090
- }
1091
- }
1092
- }
1093
-
1094
- for (let i = tokenIdx; i < line.tokens.length; i++) {
1095
- if (line.tokens[i].type === 'DIRECTIVE') {
1096
- directives.push(this.parseDirectiveInline(line.tokens, i))
1097
- }
1098
- }
1099
-
1100
- this.advance()
1101
- const fields = this.parseFieldDefinitions(baseIndent)
1102
-
1103
- return new AST.InterfaceTypeDefinitionNode(null, name, interfaces, directives, fields)
1104
- }
1105
-
1106
- parseUnionTypeDefinition() {
1107
- const line = this.currentLine()
1108
- let name = null
1109
- let directives = []
1110
- let types = []
1111
- let tokenIdx = 1
1112
-
1113
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
1114
- name = new AST.NameNode(line.tokens[tokenIdx].value)
1115
- tokenIdx++
1116
- }
1117
-
1118
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'EQUALS') {
1119
- tokenIdx++
1120
- }
1121
-
1122
- while (tokenIdx < line.tokens.length) {
1123
- if (line.tokens[tokenIdx].type === 'DIRECTIVE') break
1124
- if (line.tokens[tokenIdx].type === 'IDENTIFIER') {
1125
- types.push(new AST.NamedTypeNode(new AST.NameNode(line.tokens[tokenIdx].value)))
1126
- tokenIdx++
1127
- }
1128
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'PIPE') {
1129
- tokenIdx++
1130
- } else if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'COMMA') {
1131
- tokenIdx++
1132
- } else {
1133
- break
1134
- }
1135
- }
1136
-
1137
- for (let i = tokenIdx; i < line.tokens.length; i++) {
1138
- if (line.tokens[i].type === 'DIRECTIVE') {
1139
- directives.push(this.parseDirectiveInline(line.tokens, i))
1140
- }
1141
- }
1142
-
1143
- this.advance()
1144
-
1145
- return new AST.UnionTypeDefinitionNode(null, name, directives, types)
1146
- }
1147
-
1148
- parseEnumTypeDefinition() {
1149
- const line = this.currentLine()
1150
- const baseIndent = line.indent
1151
- let name = null
1152
- let directives = []
1153
- let tokenIdx = 1
1154
-
1155
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
1156
- name = new AST.NameNode(line.tokens[tokenIdx].value)
1157
- tokenIdx++
1158
- }
1159
-
1160
- for (let i = tokenIdx; i < line.tokens.length; i++) {
1161
- if (line.tokens[i].type === 'DIRECTIVE') {
1162
- directives.push(this.parseDirectiveInline(line.tokens, i))
1163
- }
1164
- }
1165
-
1166
- this.advance()
1167
- const values = this.parseEnumValues(baseIndent)
1168
-
1169
- return new AST.EnumTypeDefinitionNode(null, name, directives, values)
1170
- }
1171
-
1172
- parseEnumValues(parentIndent) {
1173
- const values = []
1174
-
1175
- while (this.pos < this.tokens.length) {
1176
- const line = this.currentLine()
1177
- if (!line || line.indent <= parentIndent) break
1178
-
1179
- let description = null
1180
- let tokenIdx = 0
1181
-
1182
- if (line.tokens[0] && (line.tokens[0].type === 'STRING' || line.tokens[0].type === 'BLOCK_STRING')) {
1183
- description = new AST.StringValueNode(line.tokens[0].value, line.tokens[0].type === 'BLOCK_STRING')
1184
- tokenIdx++
1185
- }
1186
-
1187
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
1188
- const name = new AST.NameNode(line.tokens[tokenIdx].value)
1189
- tokenIdx++
1190
-
1191
- const directives = []
1192
- for (let i = tokenIdx; i < line.tokens.length; i++) {
1193
- if (line.tokens[i].type === 'DIRECTIVE') {
1194
- directives.push(this.parseDirectiveInline(line.tokens, i))
1195
- }
1196
- }
1197
-
1198
- values.push(new AST.EnumValueDefinitionNode(description, name, directives))
1199
- }
1200
-
1201
- this.advance()
1202
- }
1203
-
1204
- return values
1205
- }
1206
-
1207
- parseScalarTypeDefinition() {
1208
- const line = this.currentLine()
1209
- let name = null
1210
- let directives = []
1211
- let tokenIdx = 1
1212
-
1213
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
1214
- name = new AST.NameNode(line.tokens[tokenIdx].value)
1215
- tokenIdx++
1216
- }
1217
-
1218
- for (let i = tokenIdx; i < line.tokens.length; i++) {
1219
- if (line.tokens[i].type === 'DIRECTIVE') {
1220
- directives.push(this.parseDirectiveInline(line.tokens, i))
1221
- }
1222
- }
1223
-
1224
- this.advance()
1225
-
1226
- return new AST.ScalarTypeDefinitionNode(null, name, directives)
1227
- }
1228
-
1229
- parseSchemaDefinition() {
1230
- const line = this.currentLine()
1231
- const baseIndent = line.indent
1232
- let directives = []
1233
- let tokenIdx = 1
1234
-
1235
- for (let i = tokenIdx; i < line.tokens.length; i++) {
1236
- if (line.tokens[i].type === 'DIRECTIVE') {
1237
- directives.push(this.parseDirectiveInline(line.tokens, i))
1238
- }
1239
- }
1240
-
1241
- this.advance()
1242
- const operationTypes = this.parseOperationTypes(baseIndent)
1243
-
1244
- return new AST.SchemaDefinitionNode(null, directives, operationTypes)
1245
- }
1246
-
1247
- parseOperationTypes(parentIndent) {
1248
- const operationTypes = []
1249
-
1250
- while (this.pos < this.tokens.length) {
1251
- const line = this.currentLine()
1252
- if (!line || line.indent <= parentIndent) break
1253
-
1254
- if (line.tokens[0] && line.tokens[0].type === 'IDENTIFIER') {
1255
- const operation = this.translateKeyword(line.tokens[0].value)
1256
- let type = null
1257
-
1258
- if (line.tokens[1] && line.tokens[1].type === 'COLON') {
1259
- if (line.tokens[2] && line.tokens[2].type === 'IDENTIFIER') {
1260
- type = new AST.NamedTypeNode(new AST.NameNode(line.tokens[2].value))
1261
- }
1262
- }
1263
-
1264
- if (type) {
1265
- operationTypes.push(new AST.OperationTypeDefinitionNode(operation, type))
1266
- }
1267
- }
1268
-
1269
- this.advance()
1270
- }
1271
-
1272
- return operationTypes
1273
- }
1274
-
1275
- parseDirectiveDefinition() {
1276
- const line = this.currentLine()
1277
- let name = null
1278
- let args = []
1279
- let repeatable = false
1280
- let locations = []
1281
- let tokenIdx = 1
1282
-
1283
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'DIRECTIVE') {
1284
- name = new AST.NameNode(line.tokens[tokenIdx].value.substring(1))
1285
- tokenIdx++
1286
- }
1287
-
1288
- if (line.tokens[tokenIdx] && this.translateKeyword(line.tokens[tokenIdx].value) === 'on') {
1289
- tokenIdx++
1290
- }
1291
-
1292
- while (tokenIdx < line.tokens.length) {
1293
- if (line.tokens[tokenIdx].type === 'IDENTIFIER') {
1294
- const loc = line.tokens[tokenIdx].value.toUpperCase()
1295
- locations.push(new AST.NameNode(loc))
1296
- tokenIdx++
1297
- }
1298
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'PIPE') {
1299
- tokenIdx++
1300
- } else if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'COMMA') {
1301
- tokenIdx++
1302
- } else {
1303
- break
1304
- }
1305
- }
1306
-
1307
- this.advance()
1308
-
1309
- return new AST.DirectiveDefinitionNode(null, name, args, repeatable, locations)
1310
- }
1311
-
1312
- parseTypeExtension() {
1313
- const line = this.currentLine()
1314
- let tokenIdx = 1
1315
-
1316
- if (line.tokens[tokenIdx]) {
1317
- const extendedType = this.translateKeyword(line.tokens[tokenIdx].value)
1318
-
1319
- switch (extendedType) {
1320
- case 'type':
1321
- return this.parseObjectTypeExtension()
1322
- case 'input':
1323
- return this.parseInputObjectTypeExtension()
1324
- case 'interface':
1325
- return this.parseInterfaceTypeExtension()
1326
- case 'union':
1327
- return this.parseUnionTypeExtension()
1328
- case 'enum':
1329
- return this.parseEnumTypeExtension()
1330
- case 'scalar':
1331
- return this.parseScalarTypeExtension()
1332
- case 'schema':
1333
- return this.parseSchemaExtension()
1334
- }
1335
- }
1336
-
1337
- this.advance()
1338
- return null
1339
- }
1340
-
1341
- parseObjectTypeExtension() {
1342
- const line = this.currentLine()
1343
- const baseIndent = line.indent
1344
- let name = null
1345
- let interfaces = []
1346
- let directives = []
1347
- let tokenIdx = 2
1348
-
1349
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
1350
- name = new AST.NameNode(line.tokens[tokenIdx].value)
1351
- tokenIdx++
1352
- }
1353
-
1354
- if (line.tokens[tokenIdx] && this.translateKeyword(line.tokens[tokenIdx].value) === 'implements') {
1355
- tokenIdx++
1356
- while (tokenIdx < line.tokens.length) {
1357
- if (line.tokens[tokenIdx].type === 'DIRECTIVE') break
1358
- if (line.tokens[tokenIdx].type === 'IDENTIFIER') {
1359
- interfaces.push(new AST.NamedTypeNode(new AST.NameNode(line.tokens[tokenIdx].value)))
1360
- tokenIdx++
1361
- }
1362
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'COMMA') {
1363
- tokenIdx++
1364
- } else {
1365
- break
1366
- }
1367
- }
1368
- }
1369
-
1370
- for (let i = tokenIdx; i < line.tokens.length; i++) {
1371
- if (line.tokens[i].type === 'DIRECTIVE') {
1372
- directives.push(this.parseDirectiveInline(line.tokens, i))
1373
- }
1374
- }
1375
-
1376
- this.advance()
1377
- const fields = this.parseFieldDefinitions(baseIndent)
1378
-
1379
- return new AST.ObjectTypeExtensionNode(name, interfaces, directives, fields)
1380
- }
1381
-
1382
- parseInputObjectTypeExtension() {
1383
- const line = this.currentLine()
1384
- const baseIndent = line.indent
1385
- let name = null
1386
- let directives = []
1387
- let tokenIdx = 2
1388
-
1389
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
1390
- name = new AST.NameNode(line.tokens[tokenIdx].value)
1391
- tokenIdx++
1392
- }
1393
-
1394
- for (let i = tokenIdx; i < line.tokens.length; i++) {
1395
- if (line.tokens[i].type === 'DIRECTIVE') {
1396
- directives.push(this.parseDirectiveInline(line.tokens, i))
1397
- }
1398
- }
1399
-
1400
- this.advance()
1401
- const fields = this.parseInputFieldDefinitions(baseIndent)
1402
-
1403
- return new AST.InputObjectTypeExtensionNode(name, directives, fields)
1404
- }
1405
-
1406
- parseInterfaceTypeExtension() {
1407
- const line = this.currentLine()
1408
- const baseIndent = line.indent
1409
- let name = null
1410
- let interfaces = []
1411
- let directives = []
1412
- let tokenIdx = 2
1413
-
1414
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
1415
- name = new AST.NameNode(line.tokens[tokenIdx].value)
1416
- tokenIdx++
1417
- }
1418
-
1419
- for (let i = tokenIdx; i < line.tokens.length; i++) {
1420
- if (line.tokens[i].type === 'DIRECTIVE') {
1421
- directives.push(this.parseDirectiveInline(line.tokens, i))
1422
- }
1423
- }
1424
-
1425
- this.advance()
1426
- const fields = this.parseFieldDefinitions(baseIndent)
1427
-
1428
- return new AST.InterfaceTypeExtensionNode(name, interfaces, directives, fields)
1429
- }
1430
-
1431
- parseUnionTypeExtension() {
1432
- const line = this.currentLine()
1433
- let name = null
1434
- let directives = []
1435
- let types = []
1436
- let tokenIdx = 2
1437
-
1438
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
1439
- name = new AST.NameNode(line.tokens[tokenIdx].value)
1440
- tokenIdx++
1441
- }
1442
-
1443
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'EQUALS') {
1444
- tokenIdx++
1445
- }
1446
-
1447
- while (tokenIdx < line.tokens.length) {
1448
- if (line.tokens[tokenIdx].type === 'DIRECTIVE') break
1449
- if (line.tokens[tokenIdx].type === 'IDENTIFIER') {
1450
- types.push(new AST.NamedTypeNode(new AST.NameNode(line.tokens[tokenIdx].value)))
1451
- tokenIdx++
1452
- }
1453
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'PIPE') {
1454
- tokenIdx++
1455
- } else {
1456
- break
1457
- }
1458
- }
1459
-
1460
- this.advance()
1461
-
1462
- return new AST.UnionTypeExtensionNode(name, directives, types)
1463
- }
1464
-
1465
- parseEnumTypeExtension() {
1466
- const line = this.currentLine()
1467
- const baseIndent = line.indent
1468
- let name = null
1469
- let directives = []
1470
- let tokenIdx = 2
1471
-
1472
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
1473
- name = new AST.NameNode(line.tokens[tokenIdx].value)
1474
- tokenIdx++
1475
- }
1476
-
1477
- for (let i = tokenIdx; i < line.tokens.length; i++) {
1478
- if (line.tokens[i].type === 'DIRECTIVE') {
1479
- directives.push(this.parseDirectiveInline(line.tokens, i))
1480
- }
1481
- }
1482
-
1483
- this.advance()
1484
- const values = this.parseEnumValues(baseIndent)
1485
-
1486
- return new AST.EnumTypeExtensionNode(name, directives, values)
1487
- }
1488
-
1489
- parseScalarTypeExtension() {
1490
- const line = this.currentLine()
1491
- let name = null
1492
- let directives = []
1493
- let tokenIdx = 2
1494
-
1495
- if (line.tokens[tokenIdx] && line.tokens[tokenIdx].type === 'IDENTIFIER') {
1496
- name = new AST.NameNode(line.tokens[tokenIdx].value)
1497
- tokenIdx++
1498
- }
1499
-
1500
- for (let i = tokenIdx; i < line.tokens.length; i++) {
1501
- if (line.tokens[i].type === 'DIRECTIVE') {
1502
- directives.push(this.parseDirectiveInline(line.tokens, i))
1503
- }
1504
- }
1505
-
1506
- this.advance()
1507
-
1508
- return new AST.ScalarTypeExtensionNode(name, directives)
1509
- }
1510
-
1511
- parseSchemaExtension() {
1512
- const line = this.currentLine()
1513
- const baseIndent = line.indent
1514
- let directives = []
1515
- let tokenIdx = 2
1516
-
1517
- for (let i = tokenIdx; i < line.tokens.length; i++) {
1518
- if (line.tokens[i].type === 'DIRECTIVE') {
1519
- directives.push(this.parseDirectiveInline(line.tokens, i))
1520
- }
1521
- }
1522
-
1523
- this.advance()
1524
- const operationTypes = this.parseOperationTypes(baseIndent)
1525
-
1526
- return new AST.SchemaExtensionNode(directives, operationTypes)
1527
- }
1528
- }
1529
-
1530
- class GraphQLCodeGenerator {
1531
- constructor() {
1532
- this.indent = 0
1533
- }
1534
-
1535
- generate(ast) {
1536
- if (!ast) return ''
1537
-
1538
- switch (ast.type) {
1539
- case 'Document':
1540
- return ast.definitions.map(d => this.generate(d)).join('\n\n')
1541
-
1542
- case 'OperationDefinition':
1543
- return this.generateOperation(ast)
1544
-
1545
- case 'FragmentDefinition':
1546
- return this.generateFragment(ast)
1547
-
1548
- case 'ObjectTypeDefinition':
1549
- return this.generateObjectType(ast)
1550
-
1551
- case 'InputObjectTypeDefinition':
1552
- return this.generateInputType(ast)
1553
-
1554
- case 'InterfaceTypeDefinition':
1555
- return this.generateInterface(ast)
1556
-
1557
- case 'UnionTypeDefinition':
1558
- return this.generateUnion(ast)
1559
-
1560
- case 'EnumTypeDefinition':
1561
- return this.generateEnum(ast)
1562
-
1563
- case 'ScalarTypeDefinition':
1564
- return this.generateScalar(ast)
1565
-
1566
- case 'SchemaDefinition':
1567
- return this.generateSchema(ast)
1568
-
1569
- case 'DirectiveDefinition':
1570
- return this.generateDirectiveDefinition(ast)
1571
-
1572
- case 'ObjectTypeExtension':
1573
- case 'InputObjectTypeExtension':
1574
- case 'InterfaceTypeExtension':
1575
- case 'UnionTypeExtension':
1576
- case 'EnumTypeExtension':
1577
- case 'ScalarTypeExtension':
1578
- case 'SchemaExtension':
1579
- return this.generateExtension(ast)
1580
-
1581
- default:
1582
- return ''
1583
- }
1584
- }
1585
-
1586
- generateOperation(ast) {
1587
- let result = ast.operation
1588
-
1589
- if (ast.name) {
1590
- result += ' ' + ast.name.value
1591
- }
1592
-
1593
- if (ast.variableDefinitions && ast.variableDefinitions.length > 0) {
1594
- result += '(' + ast.variableDefinitions.map(v => this.generateVariableDefinition(v)).join(', ') + ')'
1595
- }
1596
-
1597
- if (ast.directives && ast.directives.length > 0) {
1598
- result += ' ' + ast.directives.map(d => this.generateDirective(d)).join(' ')
1599
- }
1600
-
1601
- result += ' ' + this.generateSelectionSet(ast.selectionSet)
1602
-
1603
- return result
1604
- }
1605
-
1606
- generateVariableDefinition(ast) {
1607
- let result = '$' + ast.variable.name.value + ': ' + this.generateType(ast.type)
1608
-
1609
- if (ast.defaultValue) {
1610
- result += ' = ' + this.generateValue(ast.defaultValue)
1611
- }
1612
-
1613
- return result
1614
- }
1615
-
1616
- generateType(ast) {
1617
- if (!ast) return ''
1618
-
1619
- switch (ast.type) {
1620
- case 'NamedType':
1621
- return ast.name.value
1622
-
1623
- case 'ListType':
1624
- return '[' + this.generateType(ast.type) + ']'
1625
-
1626
- case 'NonNullType':
1627
- return this.generateType(ast.type) + '!'
1628
-
1629
- default:
1630
- return ''
1631
- }
1632
- }
1633
-
1634
- generateValue(ast) {
1635
- if (!ast) return 'null'
1636
-
1637
- switch (ast.type) {
1638
- case 'IntValue':
1639
- return String(ast.value)
1640
-
1641
- case 'FloatValue':
1642
- return String(ast.value)
1643
-
1644
- case 'StringValue':
1645
- if (ast.block) {
1646
- return '"""' + ast.value + '"""'
1647
- }
1648
- return '"' + ast.value.replace(/"/g, '\\"') + '"'
1649
-
1650
- case 'BooleanValue':
1651
- return ast.value ? 'true' : 'false'
1652
-
1653
- case 'NullValue':
1654
- return 'null'
1655
-
1656
- case 'EnumValue':
1657
- return ast.value
1658
-
1659
- case 'Variable':
1660
- return '$' + ast.name.value
1661
-
1662
- case 'ListValue':
1663
- return '[' + ast.values.map(v => this.generateValue(v)).join(', ') + ']'
1664
-
1665
- case 'ObjectValue':
1666
- return '{' + ast.fields.map(f => f.name.value + ': ' + this.generateValue(f.value)).join(', ') + '}'
1667
-
1668
- default:
1669
- return ''
1670
- }
1671
- }
1672
-
1673
- generateDirective(ast) {
1674
- let result = '@' + ast.name.value
1675
-
1676
- if (ast.arguments && ast.arguments.length > 0) {
1677
- result += '(' + ast.arguments.map(a => a.name.value + ': ' + this.generateValue(a.value)).join(', ') + ')'
1678
- }
1679
-
1680
- return result
1681
- }
1682
-
1683
- generateSelectionSet(ast) {
1684
- if (!ast || !ast.selections || ast.selections.length === 0) {
1685
- return ''
1686
- }
1687
-
1688
- this.indent++
1689
- const selections = ast.selections.map(s => this.generateSelection(s)).join('\n')
1690
- this.indent--
1691
-
1692
- return '{\n' + selections + '\n' + this.getIndent() + '}'
1693
- }
1694
-
1695
- generateSelection(ast) {
1696
- const prefix = this.getIndent()
1697
-
1698
- switch (ast.type) {
1699
- case 'Field':
1700
- return prefix + this.generateField(ast)
1701
-
1702
- case 'FragmentSpread':
1703
- return prefix + '...' + ast.name.value + this.generateDirectives(ast.directives)
1704
-
1705
- case 'InlineFragment':
1706
- let result = prefix + '...'
1707
- if (ast.typeCondition) {
1708
- result += ' on ' + ast.typeCondition.name.value
1709
- }
1710
- result += this.generateDirectives(ast.directives)
1711
- result += ' ' + this.generateSelectionSet(ast.selectionSet)
1712
- return result
1713
-
1714
- default:
1715
- return ''
1716
- }
1717
- }
1718
-
1719
- generateField(ast) {
1720
- let result = ''
1721
-
1722
- if (ast.alias) {
1723
- result += ast.alias.value + ': '
1724
- }
1725
-
1726
- result += ast.name.value
1727
-
1728
- if (ast.arguments && ast.arguments.length > 0) {
1729
- result += '(' + ast.arguments.map(a => a.name.value + ': ' + this.generateValue(a.value)).join(', ') + ')'
1730
- }
1731
-
1732
- result += this.generateDirectives(ast.directives)
1733
-
1734
- if (ast.selectionSet && ast.selectionSet.selections && ast.selectionSet.selections.length > 0) {
1735
- result += ' ' + this.generateSelectionSet(ast.selectionSet)
1736
- }
1737
-
1738
- return result
1739
- }
1740
-
1741
- generateDirectives(directives) {
1742
- if (!directives || directives.length === 0) return ''
1743
- return ' ' + directives.map(d => this.generateDirective(d)).join(' ')
1744
- }
1745
-
1746
- generateFragment(ast) {
1747
- let result = 'fragment ' + ast.name.value
1748
-
1749
- if (ast.typeCondition) {
1750
- result += ' on ' + ast.typeCondition.name.value
1751
- }
1752
-
1753
- result += this.generateDirectives(ast.directives)
1754
- result += ' ' + this.generateSelectionSet(ast.selectionSet)
1755
-
1756
- return result
1757
- }
1758
-
1759
- generateObjectType(ast) {
1760
- let result = ''
1761
-
1762
- if (ast.description) {
1763
- result += this.generateValue(ast.description) + '\n'
1764
- }
1765
-
1766
- result += 'type ' + ast.name.value
1767
-
1768
- if (ast.interfaces && ast.interfaces.length > 0) {
1769
- result += ' implements ' + ast.interfaces.map(i => i.name.value).join(' & ')
1770
- }
1771
-
1772
- result += this.generateDirectives(ast.directives)
1773
- result += ' {\n'
1774
-
1775
- this.indent++
1776
- result += ast.fields.map(f => this.getIndent() + this.generateFieldDefinition(f)).join('\n')
1777
- this.indent--
1778
-
1779
- result += '\n}'
1780
-
1781
- return result
1782
- }
1783
-
1784
- generateFieldDefinition(ast) {
1785
- let result = ''
1786
-
1787
- if (ast.description) {
1788
- result += this.generateValue(ast.description) + '\n' + this.getIndent()
1789
- }
1790
-
1791
- result += ast.name.value
1792
-
1793
- if (ast.arguments && ast.arguments.length > 0) {
1794
- result += '(' + ast.arguments.map(a => this.generateInputValueDefinition(a)).join(', ') + ')'
1795
- }
1796
-
1797
- result += ': ' + this.generateType(ast.type)
1798
- result += this.generateDirectives(ast.directives)
1799
-
1800
- return result
1801
- }
1802
-
1803
- generateInputValueDefinition(ast) {
1804
- let result = ast.name.value + ': ' + this.generateType(ast.type)
1805
-
1806
- if (ast.defaultValue) {
1807
- result += ' = ' + this.generateValue(ast.defaultValue)
1808
- }
1809
-
1810
- result += this.generateDirectives(ast.directives)
1811
-
1812
- return result
1813
- }
1814
-
1815
- generateInputType(ast) {
1816
- let result = ''
1817
-
1818
- if (ast.description) {
1819
- result += this.generateValue(ast.description) + '\n'
1820
- }
1821
-
1822
- result += 'input ' + ast.name.value
1823
- result += this.generateDirectives(ast.directives)
1824
- result += ' {\n'
1825
-
1826
- this.indent++
1827
- result += ast.fields.map(f => this.getIndent() + this.generateInputValueDefinition(f)).join('\n')
1828
- this.indent--
1829
-
1830
- result += '\n}'
1831
-
1832
- return result
1833
- }
1834
-
1835
- generateInterface(ast) {
1836
- let result = ''
1837
-
1838
- if (ast.description) {
1839
- result += this.generateValue(ast.description) + '\n'
1840
- }
1841
-
1842
- result += 'interface ' + ast.name.value
1843
-
1844
- if (ast.interfaces && ast.interfaces.length > 0) {
1845
- result += ' implements ' + ast.interfaces.map(i => i.name.value).join(' & ')
1846
- }
1847
-
1848
- result += this.generateDirectives(ast.directives)
1849
- result += ' {\n'
1850
-
1851
- this.indent++
1852
- result += ast.fields.map(f => this.getIndent() + this.generateFieldDefinition(f)).join('\n')
1853
- this.indent--
1854
-
1855
- result += '\n}'
1856
-
1857
- return result
1858
- }
1859
-
1860
- generateUnion(ast) {
1861
- let result = ''
1862
-
1863
- if (ast.description) {
1864
- result += this.generateValue(ast.description) + '\n'
1865
- }
1866
-
1867
- result += 'union ' + ast.name.value
1868
- result += this.generateDirectives(ast.directives)
1869
- result += ' = ' + ast.types.map(t => t.name.value).join(' | ')
1870
-
1871
- return result
1872
- }
1873
-
1874
- generateEnum(ast) {
1875
- let result = ''
1876
-
1877
- if (ast.description) {
1878
- result += this.generateValue(ast.description) + '\n'
1879
- }
1880
-
1881
- result += 'enum ' + ast.name.value
1882
- result += this.generateDirectives(ast.directives)
1883
- result += ' {\n'
1884
-
1885
- this.indent++
1886
- result += ast.values.map(v => {
1887
- let line = this.getIndent()
1888
- if (v.description) {
1889
- line = this.getIndent() + this.generateValue(v.description) + '\n' + this.getIndent()
1890
- }
1891
- return line + v.name.value + this.generateDirectives(v.directives)
1892
- }).join('\n')
1893
- this.indent--
1894
-
1895
- result += '\n}'
1896
-
1897
- return result
1898
- }
1899
-
1900
- generateScalar(ast) {
1901
- let result = ''
1902
-
1903
- if (ast.description) {
1904
- result += this.generateValue(ast.description) + '\n'
1905
- }
1906
-
1907
- result += 'scalar ' + ast.name.value
1908
- result += this.generateDirectives(ast.directives)
1909
-
1910
- return result
1911
- }
1912
-
1913
- generateSchema(ast) {
1914
- let result = 'schema'
1915
- result += this.generateDirectives(ast.directives)
1916
- result += ' {\n'
1917
-
1918
- this.indent++
1919
- result += ast.operationTypes.map(o => this.getIndent() + o.operation + ': ' + o.type.name.value).join('\n')
1920
- this.indent--
1921
-
1922
- result += '\n}'
1923
-
1924
- return result
1925
- }
1926
-
1927
- generateDirectiveDefinition(ast) {
1928
- let result = ''
1929
-
1930
- if (ast.description) {
1931
- result += this.generateValue(ast.description) + '\n'
1932
- }
1933
-
1934
- result += 'directive @' + ast.name.value
1935
-
1936
- if (ast.arguments && ast.arguments.length > 0) {
1937
- result += '(' + ast.arguments.map(a => this.generateInputValueDefinition(a)).join(', ') + ')'
1938
- }
1939
-
1940
- if (ast.repeatable) {
1941
- result += ' repeatable'
1942
- }
1943
-
1944
- result += ' on ' + ast.locations.map(l => l.value).join(' | ')
1945
-
1946
- return result
1947
- }
1948
-
1949
- generateExtension(ast) {
1950
- const typeMap = {
1951
- 'ObjectTypeExtension': 'type',
1952
- 'InputObjectTypeExtension': 'input',
1953
- 'InterfaceTypeExtension': 'interface',
1954
- 'UnionTypeExtension': 'union',
1955
- 'EnumTypeExtension': 'enum',
1956
- 'ScalarTypeExtension': 'scalar',
1957
- 'SchemaExtension': 'schema'
1958
- }
1959
-
1960
- let result = 'extend ' + typeMap[ast.type]
1961
-
1962
- if (ast.name) {
1963
- result += ' ' + ast.name.value
1964
- }
1965
-
1966
- if (ast.interfaces && ast.interfaces.length > 0) {
1967
- result += ' implements ' + ast.interfaces.map(i => i.name.value).join(' & ')
1968
- }
1969
-
1970
- result += this.generateDirectives(ast.directives)
1971
-
1972
- if (ast.fields && ast.fields.length > 0) {
1973
- result += ' {\n'
1974
- this.indent++
1975
- result += ast.fields.map(f => this.getIndent() + this.generateFieldDefinition(f)).join('\n')
1976
- this.indent--
1977
- result += '\n}'
1978
- }
1979
-
1980
- if (ast.types && ast.types.length > 0) {
1981
- result += ' = ' + ast.types.map(t => t.name.value).join(' | ')
1982
- }
1983
-
1984
- if (ast.values && ast.values.length > 0) {
1985
- result += ' {\n'
1986
- this.indent++
1987
- result += ast.values.map(v => this.getIndent() + v.name.value + this.generateDirectives(v.directives)).join('\n')
1988
- this.indent--
1989
- result += '\n}'
1990
- }
1991
-
1992
- if (ast.operationTypes && ast.operationTypes.length > 0) {
1993
- result += ' {\n'
1994
- this.indent++
1995
- result += ast.operationTypes.map(o => this.getIndent() + o.operation + ': ' + o.type.name.value).join('\n')
1996
- this.indent--
1997
- result += '\n}'
1998
- }
1999
-
2000
- return result
2001
- }
2002
-
2003
- getIndent() {
2004
- return ' '.repeat(this.indent)
2005
- }
2006
- }
2007
-
2008
- module.exports = {
2009
- EtherGraphQLParser,
2010
- GraphQLCodeGenerator
2011
- }