ether-code 0.1.8 → 0.2.0

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.
@@ -0,0 +1,3059 @@
1
+ const fs = require('fs')
2
+ const { EtherLexer, Token, TokenType } = require('./lexer/ether-lexer')
3
+
4
+ class EtherParser {
5
+ constructor(options = {}) {
6
+ this.tokens = []
7
+ this.pos = 0
8
+ this.currentIndent = 0
9
+ this.i18n = {}
10
+ this.reverseMaps = {}
11
+ this.targetLang = options.targetLang || 'auto'
12
+
13
+ this.loadAllI18n(options.i18nDir || './i18n')
14
+ }
15
+
16
+ loadAllI18n(dir) {
17
+ const files = [
18
+ 'i18n-css.json', 'i18n-html.json', 'i18n-js.json',
19
+ 'i18n-php.json', 'i18n-python.json', 'i18n-sql.json',
20
+ 'i18n-ruby.json', 'i18n-node.json', 'i18n-react.json',
21
+ 'i18n-ts.json', 'i18n-graphql.json'
22
+ ]
23
+
24
+ for (const file of files) {
25
+ const lang = file.replace('i18n-', '').replace('.json', '')
26
+ const path = `${dir}/${file}`
27
+
28
+ try {
29
+ if (fs.existsSync(path)) {
30
+ this.i18n[lang] = JSON.parse(fs.readFileSync(path, 'utf-8'))
31
+ this.buildReverseMap(lang)
32
+ }
33
+ } catch (e) {
34
+ }
35
+ }
36
+ }
37
+
38
+ buildReverseMap(lang) {
39
+ this.reverseMaps[lang] = {}
40
+ const data = this.i18n[lang]
41
+
42
+ const processSection = (section, targetKey = lang) => {
43
+ if (!section || typeof section !== 'object') return
44
+
45
+ for (const [key, translations] of Object.entries(section)) {
46
+ if (translations && typeof translations === 'object') {
47
+ if (translations.fr) {
48
+ const frTerms = Array.isArray(translations.fr) ? translations.fr : [translations.fr]
49
+ const target = translations[targetKey] || translations.css || translations.html || translations.js || translations.value
50
+
51
+ for (const term of frTerms) {
52
+ if (typeof term === 'string') {
53
+ this.reverseMaps[lang][term.toLowerCase()] = target
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+
61
+ for (const [sectionName, sectionData] of Object.entries(data)) {
62
+ processSection(sectionData)
63
+ }
64
+ }
65
+
66
+ peek(offset = 0) {
67
+ const idx = this.pos + offset
68
+ return idx < this.tokens.length ? this.tokens[idx] : null
69
+ }
70
+
71
+ current() {
72
+ return this.tokens[this.pos] || null
73
+ }
74
+
75
+ advance() {
76
+ const token = this.tokens[this.pos]
77
+ this.pos++
78
+ return token
79
+ }
80
+
81
+ expect(type) {
82
+ const token = this.current()
83
+ if (!token || token.type !== type) {
84
+ throw new Error(`Attendu ${type}, reçu ${token ? token.type : 'EOF'}`)
85
+ }
86
+ return this.advance()
87
+ }
88
+
89
+ match(type) {
90
+ if (this.current() && this.current().type === type) {
91
+ return this.advance()
92
+ }
93
+ return null
94
+ }
95
+
96
+ matchValue(value) {
97
+ const token = this.current()
98
+ if (!token || token.value === null || token.value === undefined) return null
99
+ const tokenVal = String(token.value).toLowerCase()
100
+ if (tokenVal === value.toLowerCase()) {
101
+ return this.advance()
102
+ }
103
+ return null
104
+ }
105
+
106
+ isAtEnd() {
107
+ return this.pos >= this.tokens.length || (this.current() && this.current().type === TokenType.EOF)
108
+ }
109
+
110
+ skipNewlines() {
111
+ while (this.match(TokenType.NEWLINE)) {}
112
+ }
113
+
114
+ detectTargetLanguage(source) {
115
+ const lower = source.toLowerCase()
116
+
117
+ if (/^\s*(document|page|<!doctype|<html|tete|corps|entete|navigation|section|article)/m.test(lower)) {
118
+ return 'html'
119
+ }
120
+
121
+ if (/^\s*(\.|#|@media|@keyframes|corps|html|body|fond|marge|remplissage|largeur|hauteur)/m.test(lower)) {
122
+ if (!/fonction|si\s|pour\s|tant que/.test(lower)) {
123
+ return 'css'
124
+ }
125
+ }
126
+
127
+ if (/^\s*(composant|etat|effet|memo|contexte|utiliser\s+(etat|effet|memo)|retourner\s*\(?\s*<)/m.test(lower)) {
128
+ return 'react'
129
+ }
130
+
131
+ if (/<[a-z]+|jsx|tsx/i.test(lower) && /fonction|composant/.test(lower)) {
132
+ return 'react'
133
+ }
134
+
135
+ if (/^\s*(creer table|inserer|selectionner|mettre a jour|supprimer|table|base de donnees)/m.test(lower)) {
136
+ return 'sql'
137
+ }
138
+
139
+ if (/^\s*(type|interface|enum|generique|<[A-Z]\w*>)/m.test(lower)) {
140
+ return 'ts'
141
+ }
142
+
143
+ if (/^\s*(schema|type\s+\w+\s*{|query|mutation|subscription|input\s+\w+)/m.test(lower)) {
144
+ return 'graphql'
145
+ }
146
+
147
+ if (/^\s*(<\?php|\$\w+|echo|inclure|require)/m.test(lower)) {
148
+ return 'php'
149
+ }
150
+
151
+ if (/^\s*(def\s+\w+|classe\s+\w+|importer\s|de\s+\w+\s+importer)/m.test(lower) && !/fin\s*$|faire\s*$/m.test(lower)) {
152
+ return 'python'
153
+ }
154
+
155
+ if (/^\s*(classe\s+\w+|def\s+\w+|fin\s*$|faire\s*$|module\s+\w+)/m.test(lower)) {
156
+ return 'ruby'
157
+ }
158
+
159
+ if (/^\s*(const\s+\w+\s*=\s*require|module\.exports|exporter\s+defaut)/m.test(lower)) {
160
+ return 'node'
161
+ }
162
+
163
+ if (/fonction|variable|constante|si\s|pour\s|tant que|retourner/.test(lower)) {
164
+ return 'js'
165
+ }
166
+
167
+ return 'js'
168
+ }
169
+
170
+ parse(source, targetLang = null) {
171
+ const lexer = new EtherLexer(source)
172
+ this.tokens = lexer.tokenize()
173
+ this.pos = 0
174
+
175
+ const detectedLang = targetLang || this.targetLang
176
+ const lang = detectedLang === 'auto' ? this.detectTargetLanguage(source) : detectedLang
177
+
178
+ switch (lang) {
179
+ case 'css':
180
+ return this.parseCSS()
181
+ case 'html':
182
+ return this.parseHTML()
183
+ case 'js':
184
+ case 'javascript':
185
+ return this.parseJS()
186
+ case 'ts':
187
+ case 'typescript':
188
+ return this.parseTS()
189
+ case 'react':
190
+ case 'jsx':
191
+ return this.parseReact()
192
+ case 'php':
193
+ return this.parsePHP()
194
+ case 'python':
195
+ case 'py':
196
+ return this.parsePython()
197
+ case 'ruby':
198
+ case 'rb':
199
+ return this.parseRuby()
200
+ case 'sql':
201
+ return this.parseSQL()
202
+ case 'node':
203
+ case 'nodejs':
204
+ return this.parseNode()
205
+ case 'graphql':
206
+ case 'gql':
207
+ return this.parseGraphQL()
208
+ default:
209
+ return this.parseJS()
210
+ }
211
+ }
212
+
213
+ parseCSS() {
214
+ const stylesheet = {
215
+ type: 'StyleSheet',
216
+ rules: []
217
+ }
218
+
219
+ this.skipNewlines()
220
+
221
+ while (!this.isAtEnd()) {
222
+ const rule = this.parseCSSRule()
223
+ if (rule) {
224
+ stylesheet.rules.push(rule)
225
+ }
226
+ this.skipNewlines()
227
+ }
228
+
229
+ return stylesheet
230
+ }
231
+
232
+ parseCSSRule() {
233
+ this.skipNewlines()
234
+ const token = this.current()
235
+ if (!token || token.type === TokenType.EOF) return null
236
+
237
+ if (token.type === TokenType.AT) {
238
+ return this.parseCSSAtRule()
239
+ }
240
+
241
+ const selector = this.parseCSSSelector()
242
+ if (!selector) return null
243
+
244
+ this.skipNewlines()
245
+ this.match(TokenType.INDENT)
246
+
247
+ const declarations = []
248
+ const nestedRules = []
249
+
250
+ while (!this.isAtEnd()) {
251
+ const current = this.current()
252
+
253
+ if (current && current.type === TokenType.DEDENT) {
254
+ this.advance()
255
+ break
256
+ }
257
+
258
+ if (current && current.type === TokenType.NEWLINE) {
259
+ this.advance()
260
+ continue
261
+ }
262
+
263
+ if (!current || current.type === TokenType.EOF) break
264
+
265
+ if (current.type === TokenType.IDENTIFIER) {
266
+ const value = current.value.toLowerCase()
267
+
268
+ if (value.startsWith('au ') || value === 'au survol' || value === 'au clic' ||
269
+ value === 'au focus' || value === 'actif' || value === 'visite' ||
270
+ value.startsWith('premier') || value.startsWith('dernier') ||
271
+ value.startsWith('avant') || value.startsWith('apres')) {
272
+ const pseudoRule = this.parseCSSPseudoBlock(selector)
273
+ if (pseudoRule) nestedRules.push(pseudoRule)
274
+ continue
275
+ }
276
+ }
277
+
278
+ const decl = this.parseCSSDeclaration()
279
+ if (decl) {
280
+ declarations.push(decl)
281
+ }
282
+ }
283
+
284
+ return {
285
+ type: 'Rule',
286
+ selector: selector,
287
+ declarations: declarations,
288
+ nestedRules: nestedRules
289
+ }
290
+ }
291
+
292
+ parseCSSSelector() {
293
+ const parts = []
294
+
295
+ while (!this.isAtEnd()) {
296
+ const token = this.current()
297
+
298
+ if (!token || token.type === TokenType.NEWLINE || token.type === TokenType.INDENT ||
299
+ token.type === TokenType.COLON || token.type === TokenType.EOF) {
300
+ break
301
+ }
302
+
303
+ if (token.type === TokenType.DOT) {
304
+ this.advance()
305
+ const name = this.current()
306
+ if (name && name.type === TokenType.IDENTIFIER) {
307
+ parts.push('.' + name.value)
308
+ this.advance()
309
+ }
310
+ } else if (token.type === TokenType.HASH) {
311
+ this.advance()
312
+ const name = this.current()
313
+ if (name && name.type === TokenType.IDENTIFIER) {
314
+ parts.push('#' + name.value)
315
+ this.advance()
316
+ }
317
+ } else if (token.type === TokenType.IDENTIFIER) {
318
+ parts.push(this.translateCSSSelector(token.value))
319
+ this.advance()
320
+ } else if (token.type === TokenType.STAR) {
321
+ parts.push('*')
322
+ this.advance()
323
+ } else if (token.type === TokenType.COMMA) {
324
+ parts.push(',')
325
+ this.advance()
326
+ } else if (token.type === TokenType.GT) {
327
+ parts.push('>')
328
+ this.advance()
329
+ } else if (token.type === TokenType.PLUS) {
330
+ parts.push('+')
331
+ this.advance()
332
+ } else if (token.type === TokenType.TILDE) {
333
+ parts.push('~')
334
+ this.advance()
335
+ } else {
336
+ break
337
+ }
338
+ }
339
+
340
+ return parts.join(' ').replace(/\s+([,>+~])\s+/g, ' $1 ').trim()
341
+ }
342
+
343
+ translateCSSSelector(selector) {
344
+ const map = this.reverseMaps.css || {}
345
+ const lower = selector.toLowerCase()
346
+
347
+ const selectorTranslations = {
348
+ 'corps': 'body',
349
+ 'html': 'html',
350
+ 'document': 'html',
351
+ 'tete': 'head',
352
+ 'titre': 'h1',
353
+ 'paragraphe': 'p',
354
+ 'lien': 'a',
355
+ 'image': 'img',
356
+ 'bouton': 'button',
357
+ 'formulaire': 'form',
358
+ 'champ': 'input',
359
+ 'liste': 'ul',
360
+ 'liste ordonnee': 'ol',
361
+ 'element liste': 'li',
362
+ 'tableau': 'table',
363
+ 'ligne': 'tr',
364
+ 'cellule': 'td',
365
+ 'entete': 'header',
366
+ 'piedpage': 'footer',
367
+ 'navigation': 'nav',
368
+ 'section': 'section',
369
+ 'article': 'article',
370
+ 'cote': 'aside',
371
+ 'principal': 'main',
372
+ 'division': 'div',
373
+ 'portee': 'span'
374
+ }
375
+
376
+ return selectorTranslations[lower] || map[lower] || selector
377
+ }
378
+
379
+ parseCSSDeclaration() {
380
+ this.skipNewlines()
381
+ const token = this.current()
382
+ if (!token || token.type !== TokenType.IDENTIFIER) return null
383
+
384
+ const property = token.value
385
+ this.advance()
386
+
387
+ let hasColon = this.match(TokenType.COLON)
388
+ let hasEquals = !hasColon && this.match(TokenType.EQUALS)
389
+
390
+ if (!hasColon && !hasEquals) {
391
+ return null
392
+ }
393
+
394
+ const valueParts = []
395
+
396
+ while (!this.isAtEnd()) {
397
+ const current = this.current()
398
+
399
+ if (!current || current.type === TokenType.NEWLINE ||
400
+ current.type === TokenType.DEDENT || current.type === TokenType.EOF) {
401
+ break
402
+ }
403
+
404
+ if (current.type === TokenType.IDENTIFIER) {
405
+ valueParts.push(current.value)
406
+ } else if (current.type === TokenType.NUMBER || current.type === TokenType.INTEGER ||
407
+ current.type === TokenType.FLOAT) {
408
+ valueParts.push(current.value)
409
+ } else if (current.type === TokenType.STRING) {
410
+ valueParts.push(current.value)
411
+ } else if (current.type === TokenType.HEX || current.type === TokenType.HASH) {
412
+ const next = this.peek(1)
413
+ if (next && (next.type === TokenType.IDENTIFIER || next.type === TokenType.NUMBER)) {
414
+ this.advance()
415
+ valueParts.push('#' + next.value)
416
+ } else {
417
+ valueParts.push('#')
418
+ }
419
+ } else if (current.type === TokenType.COMMA) {
420
+ valueParts.push(',')
421
+ } else if (current.type === TokenType.LPAREN) {
422
+ valueParts.push('(')
423
+ } else if (current.type === TokenType.RPAREN) {
424
+ valueParts.push(')')
425
+ } else if (current.type === TokenType.PERCENT) {
426
+ valueParts.push('%')
427
+ } else if (current.type === TokenType.SLASH) {
428
+ valueParts.push('/')
429
+ } else {
430
+ break
431
+ }
432
+
433
+ this.advance()
434
+ }
435
+
436
+ return {
437
+ type: 'Declaration',
438
+ property: property,
439
+ value: valueParts.join(' ').replace(/\s+/g, ' ').trim()
440
+ }
441
+ }
442
+
443
+ parseCSSPseudoBlock(parentSelector) {
444
+ const pseudoToken = this.current()
445
+ const pseudoClass = this.translatePseudoClass(pseudoToken.value)
446
+ this.advance()
447
+
448
+ this.skipNewlines()
449
+ this.match(TokenType.INDENT)
450
+
451
+ const declarations = []
452
+
453
+ while (!this.isAtEnd()) {
454
+ const current = this.current()
455
+
456
+ if (current && current.type === TokenType.DEDENT) {
457
+ this.advance()
458
+ break
459
+ }
460
+
461
+ if (current && current.type === TokenType.NEWLINE) {
462
+ this.advance()
463
+ continue
464
+ }
465
+
466
+ if (!current || current.type === TokenType.EOF) break
467
+
468
+ const decl = this.parseCSSDeclaration()
469
+ if (decl) {
470
+ declarations.push(decl)
471
+ }
472
+ }
473
+
474
+ return {
475
+ type: 'Rule',
476
+ selector: `${parentSelector}${pseudoClass}`,
477
+ declarations: declarations
478
+ }
479
+ }
480
+
481
+ translatePseudoClass(value) {
482
+ const map = {
483
+ 'au survol': ':hover',
484
+ 'au clic': ':active',
485
+ 'actif': ':active',
486
+ 'au focus': ':focus',
487
+ 'focus': ':focus',
488
+ 'visite': ':visited',
489
+ 'premier enfant': ':first-child',
490
+ 'dernier enfant': ':last-child',
491
+ 'premier de type': ':first-of-type',
492
+ 'dernier de type': ':last-of-type',
493
+ 'enfant unique': ':only-child',
494
+ 'unique de type': ':only-of-type',
495
+ 'vide': ':empty',
496
+ 'cible': ':target',
497
+ 'coche': ':checked',
498
+ 'desactive': ':disabled',
499
+ 'active': ':enabled',
500
+ 'requis': ':required',
501
+ 'optionnel': ':optional',
502
+ 'valide': ':valid',
503
+ 'invalide': ':invalid',
504
+ 'lecture seule': ':read-only',
505
+ 'lecture ecriture': ':read-write',
506
+ 'avant': '::before',
507
+ 'apres': '::after',
508
+ 'premiere lettre': '::first-letter',
509
+ 'premiere ligne': '::first-line',
510
+ 'selection': '::selection',
511
+ 'placeholder': '::placeholder',
512
+ 'marqueur': '::marker'
513
+ }
514
+
515
+ const lower = value.toLowerCase()
516
+ return map[lower] || ':' + lower.replace(/\s+/g, '-')
517
+ }
518
+
519
+ parseCSSAtRule() {
520
+ this.advance()
521
+ const nameToken = this.current()
522
+
523
+ if (!nameToken) return null
524
+
525
+ const name = nameToken.value.toLowerCase()
526
+ this.advance()
527
+
528
+ if (name === 'media' || name === 'requete media' || name === 'ecran') {
529
+ return this.parseCSSMediaQuery()
530
+ }
531
+
532
+ if (name === 'keyframes' || name === 'images cles' || name === 'animation') {
533
+ return this.parseCSSKeyframes()
534
+ }
535
+
536
+ if (name === 'import' || name === 'importer') {
537
+ return this.parseCSSImport()
538
+ }
539
+
540
+ if (name === 'font-face' || name === 'police') {
541
+ return this.parseCSSFontFace()
542
+ }
543
+
544
+ return null
545
+ }
546
+
547
+ parseCSSMediaQuery() {
548
+ const queryParts = []
549
+
550
+ while (!this.isAtEnd()) {
551
+ const token = this.current()
552
+
553
+ if (!token || token.type === TokenType.NEWLINE || token.type === TokenType.INDENT) {
554
+ break
555
+ }
556
+
557
+ queryParts.push(token.value)
558
+ this.advance()
559
+ }
560
+
561
+ this.skipNewlines()
562
+ this.match(TokenType.INDENT)
563
+
564
+ const rules = []
565
+
566
+ while (!this.isAtEnd()) {
567
+ const current = this.current()
568
+
569
+ if (current && current.type === TokenType.DEDENT) {
570
+ this.advance()
571
+ break
572
+ }
573
+
574
+ const rule = this.parseCSSRule()
575
+ if (rule) {
576
+ rules.push(rule)
577
+ }
578
+
579
+ this.skipNewlines()
580
+ }
581
+
582
+ return {
583
+ type: 'MediaQuery',
584
+ query: this.translateMediaQuery(queryParts.join(' ')),
585
+ rules: rules
586
+ }
587
+ }
588
+
589
+ translateMediaQuery(query) {
590
+ return query
591
+ .replace(/ecran/gi, 'screen')
592
+ .replace(/imprimante/gi, 'print')
593
+ .replace(/tous/gi, 'all')
594
+ .replace(/largeur min/gi, 'min-width')
595
+ .replace(/largeur max/gi, 'max-width')
596
+ .replace(/hauteur min/gi, 'min-height')
597
+ .replace(/hauteur max/gi, 'max-height')
598
+ .replace(/orientation/gi, 'orientation')
599
+ .replace(/paysage/gi, 'landscape')
600
+ .replace(/portrait/gi, 'portrait')
601
+ .replace(/et/gi, 'and')
602
+ .replace(/ou/gi, 'or')
603
+ .replace(/pas/gi, 'not')
604
+ }
605
+
606
+ parseCSSKeyframes() {
607
+ const nameToken = this.current()
608
+ const name = nameToken ? nameToken.value : 'animation'
609
+ if (nameToken) this.advance()
610
+
611
+ this.skipNewlines()
612
+ this.match(TokenType.INDENT)
613
+
614
+ const keyframes = []
615
+
616
+ while (!this.isAtEnd()) {
617
+ const current = this.current()
618
+
619
+ if (current && current.type === TokenType.DEDENT) {
620
+ this.advance()
621
+ break
622
+ }
623
+
624
+ if (current && current.type === TokenType.NEWLINE) {
625
+ this.advance()
626
+ continue
627
+ }
628
+
629
+ const keyframe = this.parseCSSKeyframe()
630
+ if (keyframe) {
631
+ keyframes.push(keyframe)
632
+ }
633
+ }
634
+
635
+ return {
636
+ type: 'Keyframes',
637
+ name: name,
638
+ keyframes: keyframes
639
+ }
640
+ }
641
+
642
+ parseCSSKeyframe() {
643
+ const token = this.current()
644
+ if (!token) return null
645
+
646
+ let selector = token.value
647
+
648
+ const selectorMap = {
649
+ 'debut': 'from',
650
+ 'fin': 'to',
651
+ 'de': 'from',
652
+ 'a': 'to',
653
+ 'vers': 'to'
654
+ }
655
+
656
+ selector = selectorMap[selector.toLowerCase()] || selector
657
+ this.advance()
658
+
659
+ this.skipNewlines()
660
+ this.match(TokenType.INDENT)
661
+
662
+ const declarations = []
663
+
664
+ while (!this.isAtEnd()) {
665
+ const current = this.current()
666
+
667
+ if (current && current.type === TokenType.DEDENT) {
668
+ this.advance()
669
+ break
670
+ }
671
+
672
+ if (current && current.type === TokenType.NEWLINE) {
673
+ this.advance()
674
+ continue
675
+ }
676
+
677
+ const decl = this.parseCSSDeclaration()
678
+ if (decl) {
679
+ declarations.push(decl)
680
+ }
681
+ }
682
+
683
+ return {
684
+ type: 'Keyframe',
685
+ selector: selector,
686
+ declarations: declarations
687
+ }
688
+ }
689
+
690
+ parseCSSImport() {
691
+ const urlToken = this.current()
692
+ const url = urlToken ? urlToken.value.replace(/['"]/g, '') : ''
693
+ if (urlToken) this.advance()
694
+
695
+ return {
696
+ type: 'Import',
697
+ url: url
698
+ }
699
+ }
700
+
701
+ parseCSSFontFace() {
702
+ this.skipNewlines()
703
+ this.match(TokenType.INDENT)
704
+
705
+ const declarations = []
706
+
707
+ while (!this.isAtEnd()) {
708
+ const current = this.current()
709
+
710
+ if (current && current.type === TokenType.DEDENT) {
711
+ this.advance()
712
+ break
713
+ }
714
+
715
+ if (current && current.type === TokenType.NEWLINE) {
716
+ this.advance()
717
+ continue
718
+ }
719
+
720
+ const decl = this.parseCSSDeclaration()
721
+ if (decl) {
722
+ declarations.push(decl)
723
+ }
724
+ }
725
+
726
+ return {
727
+ type: 'FontFace',
728
+ declarations: declarations
729
+ }
730
+ }
731
+
732
+ parseHTML() {
733
+ const document = {
734
+ type: 'Document',
735
+ children: []
736
+ }
737
+
738
+ this.skipNewlines()
739
+
740
+ while (!this.isAtEnd()) {
741
+ const node = this.parseHTMLNode()
742
+ if (node) {
743
+ document.children.push(node)
744
+ }
745
+ this.skipNewlines()
746
+ }
747
+
748
+ return document
749
+ }
750
+
751
+ parseHTMLNode() {
752
+ this.skipNewlines()
753
+ const token = this.current()
754
+
755
+ if (!token || token.type === TokenType.EOF) return null
756
+
757
+ if (token.type === TokenType.IDENTIFIER) {
758
+ return this.parseHTMLElement()
759
+ }
760
+
761
+ if (token.type === TokenType.STRING) {
762
+ this.advance()
763
+ return {
764
+ type: 'Text',
765
+ content: token.value.replace(/^["']|["']$/g, '')
766
+ }
767
+ }
768
+
769
+ this.advance()
770
+ return null
771
+ }
772
+
773
+ parseHTMLElement() {
774
+ const tagToken = this.current()
775
+ const tag = this.translateHTMLTag(tagToken.value)
776
+ this.advance()
777
+
778
+ const attributes = {}
779
+ let inlineText = null
780
+
781
+ while (!this.isAtEnd()) {
782
+ const current = this.current()
783
+
784
+ if (!current || current.type === TokenType.NEWLINE ||
785
+ current.type === TokenType.INDENT || current.type === TokenType.EOF) {
786
+ break
787
+ }
788
+
789
+ if (current.type === TokenType.STRING) {
790
+ inlineText = current.value.replace(/^["']|["']$/g, '')
791
+ this.advance()
792
+ break
793
+ }
794
+
795
+ if (current.type === TokenType.IDENTIFIER) {
796
+ const attrName = current.value
797
+ const nextToken = this.peek(1)
798
+
799
+ if (nextToken && (nextToken.type === TokenType.EQUALS || nextToken.type === TokenType.COLON)) {
800
+ this.advance()
801
+ this.advance()
802
+ const valueToken = this.current()
803
+ if (valueToken) {
804
+ if (valueToken.type === TokenType.STRING) {
805
+ attributes[attrName] = valueToken.value.replace(/^["']|["']$/g, '')
806
+ } else if (valueToken.type === TokenType.IDENTIFIER ||
807
+ valueToken.type === TokenType.NUMBER) {
808
+ attributes[attrName] = valueToken.value
809
+ }
810
+ this.advance()
811
+ }
812
+ } else {
813
+ attributes[attrName] = true
814
+ this.advance()
815
+ }
816
+ } else {
817
+ break
818
+ }
819
+ }
820
+
821
+ this.skipNewlines()
822
+
823
+ const children = []
824
+
825
+ if (inlineText) {
826
+ children.push({
827
+ type: 'Text',
828
+ content: inlineText
829
+ })
830
+ }
831
+
832
+ if (this.match(TokenType.INDENT)) {
833
+ while (!this.isAtEnd()) {
834
+ const current = this.current()
835
+
836
+ if (current && current.type === TokenType.DEDENT) {
837
+ this.advance()
838
+ break
839
+ }
840
+
841
+ const child = this.parseHTMLNode()
842
+ if (child) {
843
+ children.push(child)
844
+ }
845
+
846
+ this.skipNewlines()
847
+ }
848
+ }
849
+
850
+ return {
851
+ type: 'Element',
852
+ tag: tag,
853
+ attributes: attributes,
854
+ children: children
855
+ }
856
+ }
857
+
858
+ translateHTMLTag(tag) {
859
+ const map = this.reverseMaps.html || {}
860
+ const lower = tag.toLowerCase()
861
+
862
+ const translations = {
863
+ 'document': 'html',
864
+ 'page': 'html',
865
+ 'tete': 'head',
866
+ 'corps': 'body',
867
+ 'entete': 'header',
868
+ 'piedpage': 'footer',
869
+ 'navigation': 'nav',
870
+ 'principal': 'main',
871
+ 'section': 'section',
872
+ 'article': 'article',
873
+ 'cote': 'aside',
874
+ 'titre': 'h1',
875
+ 'titre1': 'h1',
876
+ 'titre2': 'h2',
877
+ 'titre3': 'h3',
878
+ 'titre4': 'h4',
879
+ 'titre5': 'h5',
880
+ 'titre6': 'h6',
881
+ 'sous titre': 'h2',
882
+ 'paragraphe': 'p',
883
+ 'texte': 'span',
884
+ 'division': 'div',
885
+ 'bloc': 'div',
886
+ 'lien': 'a',
887
+ 'image': 'img',
888
+ 'liste': 'ul',
889
+ 'liste ordonnee': 'ol',
890
+ 'element': 'li',
891
+ 'tableau': 'table',
892
+ 'ligne': 'tr',
893
+ 'cellule': 'td',
894
+ 'entete cellule': 'th',
895
+ 'formulaire': 'form',
896
+ 'champ': 'input',
897
+ 'zone texte': 'textarea',
898
+ 'bouton': 'button',
899
+ 'selection': 'select',
900
+ 'option': 'option',
901
+ 'etiquette': 'label',
902
+ 'gras': 'strong',
903
+ 'italique': 'em',
904
+ 'souligne': 'u',
905
+ 'barre': 's',
906
+ 'code': 'code',
907
+ 'preformate': 'pre',
908
+ 'citation': 'blockquote',
909
+ 'retour ligne': 'br',
910
+ 'saut ligne': 'br',
911
+ 'ligne horizontale': 'hr',
912
+ 'video': 'video',
913
+ 'audio': 'audio',
914
+ 'source': 'source',
915
+ 'cadre': 'iframe',
916
+ 'canvas': 'canvas',
917
+ 'toile': 'canvas',
918
+ 'figure': 'figure',
919
+ 'legende': 'figcaption',
920
+ 'details': 'details',
921
+ 'resume': 'summary',
922
+ 'dialogue': 'dialog',
923
+ 'modele': 'template',
924
+ 'emplacement': 'slot',
925
+ 'temps': 'time',
926
+ 'marque': 'mark',
927
+ 'metre': 'meter',
928
+ 'progression': 'progress',
929
+ 'sortie': 'output',
930
+ 'donnees': 'data',
931
+ 'clavier': 'kbd',
932
+ 'exemple': 'samp',
933
+ 'variable': 'var',
934
+ 'abreviation': 'abbr',
935
+ 'indice': 'sub',
936
+ 'exposant': 'sup',
937
+ 'petit': 'small',
938
+ 'cite': 'cite',
939
+ 'definition': 'dfn',
940
+ 'adresse': 'address',
941
+ 'rubis': 'ruby',
942
+ 'texte rubis': 'rt',
943
+ 'parenthese rubis': 'rp',
944
+ 'bidirectionnel': 'bdi',
945
+ 'direction': 'bdo',
946
+ 'cesure': 'wbr',
947
+ 'noscript': 'noscript',
948
+ 'sans script': 'noscript',
949
+ 'carte': 'map',
950
+ 'zone': 'area'
951
+ }
952
+
953
+ return translations[lower] || map[lower] || tag
954
+ }
955
+
956
+ parseJS() {
957
+ return this.parseProgram('js')
958
+ }
959
+
960
+ parseTS() {
961
+ return this.parseProgram('ts')
962
+ }
963
+
964
+ parseReact() {
965
+ return this.parseProgram('react')
966
+ }
967
+
968
+ parsePHP() {
969
+ return this.parseProgram('php')
970
+ }
971
+
972
+ parsePython() {
973
+ return this.parseProgram('python')
974
+ }
975
+
976
+ parseRuby() {
977
+ return this.parseProgram('ruby')
978
+ }
979
+
980
+ parseNode() {
981
+ return this.parseProgram('node')
982
+ }
983
+
984
+ parseSQL() {
985
+ return this.parseSQLProgram()
986
+ }
987
+
988
+ parseGraphQL() {
989
+ return this.parseGraphQLProgram()
990
+ }
991
+
992
+ parseProgram(lang) {
993
+ const program = {
994
+ type: 'Program',
995
+ lang: lang,
996
+ body: []
997
+ }
998
+
999
+ this.skipNewlines()
1000
+
1001
+ while (!this.isAtEnd()) {
1002
+ const statement = this.parseStatement(lang)
1003
+ if (statement) {
1004
+ program.body.push(statement)
1005
+ }
1006
+ this.skipNewlines()
1007
+ }
1008
+
1009
+ return program
1010
+ }
1011
+
1012
+ parseStatement(lang) {
1013
+ this.skipNewlines()
1014
+ const token = this.current()
1015
+
1016
+ if (!token || token.type === TokenType.EOF) return null
1017
+
1018
+ const value = token.value != null ? String(token.value).toLowerCase() : ''
1019
+
1020
+ if (this.isVariableDeclaration(value)) {
1021
+ return this.parseVariableDeclaration(lang)
1022
+ }
1023
+
1024
+ if (this.isFunctionDeclaration(value)) {
1025
+ return this.parseFunctionDeclaration(lang)
1026
+ }
1027
+
1028
+ if (this.isClassDeclaration(value)) {
1029
+ return this.parseClassDeclaration(lang)
1030
+ }
1031
+
1032
+ if (this.isConditional(value)) {
1033
+ return this.parseConditional(lang)
1034
+ }
1035
+
1036
+ if (this.isLoop(value)) {
1037
+ return this.parseLoop(lang)
1038
+ }
1039
+
1040
+ if (this.isReturn(value)) {
1041
+ return this.parseReturn(lang)
1042
+ }
1043
+
1044
+ if (this.isImport(value)) {
1045
+ return this.parseImport(lang)
1046
+ }
1047
+
1048
+ if (this.isExport(value)) {
1049
+ return this.parseExport(lang)
1050
+ }
1051
+
1052
+ return this.parseExpression(lang)
1053
+ }
1054
+
1055
+ isVariableDeclaration(value) {
1056
+ const keywords = ['variable', 'var', 'constante', 'const', 'soit', 'let', 'definir']
1057
+ return keywords.includes(value)
1058
+ }
1059
+
1060
+ isFunctionDeclaration(value) {
1061
+ const keywords = ['fonction', 'func', 'fn', 'methode', 'def', 'procedure']
1062
+ return keywords.includes(value)
1063
+ }
1064
+
1065
+ isClassDeclaration(value) {
1066
+ const keywords = ['classe', 'class', 'type', 'interface', 'struct', 'structure']
1067
+ return keywords.includes(value)
1068
+ }
1069
+
1070
+ isConditional(value) {
1071
+ const keywords = ['si', 'if', 'sinon', 'else', 'sinon si', 'elif', 'selon', 'switch', 'cas', 'case']
1072
+ return keywords.includes(value)
1073
+ }
1074
+
1075
+ isLoop(value) {
1076
+ const keywords = ['pour', 'for', 'tant que', 'while', 'faire', 'do', 'repeter', 'boucle', 'loop', 'chaque', 'each', 'pour chaque', 'foreach']
1077
+ return keywords.includes(value)
1078
+ }
1079
+
1080
+ isReturn(value) {
1081
+ const keywords = ['retourner', 'return', 'renvoyer', 'rendre']
1082
+ return keywords.includes(value)
1083
+ }
1084
+
1085
+ isImport(value) {
1086
+ const keywords = ['importer', 'import', 'depuis', 'from', 'require', 'inclure', 'include', 'utiliser', 'use']
1087
+ return keywords.includes(value)
1088
+ }
1089
+
1090
+ isExport(value) {
1091
+ const keywords = ['exporter', 'export', 'publier', 'public']
1092
+ return keywords.includes(value)
1093
+ }
1094
+
1095
+ parseVariableDeclaration(lang) {
1096
+ const kindToken = this.advance()
1097
+ const kind = this.translateVariableKind(kindToken.value, lang)
1098
+
1099
+ const nameToken = this.current()
1100
+ if (!nameToken || nameToken.type !== TokenType.IDENTIFIER) {
1101
+ return null
1102
+ }
1103
+ const name = nameToken.value
1104
+ this.advance()
1105
+
1106
+ let typeAnnotation = null
1107
+ if (this.match(TokenType.COLON)) {
1108
+ typeAnnotation = this.parseType(lang)
1109
+ }
1110
+
1111
+ let init = null
1112
+ if (this.match(TokenType.EQUALS)) {
1113
+ init = this.parseExpression(lang)
1114
+ }
1115
+
1116
+ return {
1117
+ type: 'VariableDeclaration',
1118
+ kind: kind,
1119
+ name: name,
1120
+ typeAnnotation: typeAnnotation,
1121
+ init: init
1122
+ }
1123
+ }
1124
+
1125
+ translateVariableKind(value, lang) {
1126
+ const lower = value.toLowerCase()
1127
+
1128
+ if (lower === 'constante' || lower === 'const') {
1129
+ return 'const'
1130
+ }
1131
+ if (lower === 'variable' || lower === 'var') {
1132
+ if (lang === 'js' || lang === 'ts' || lang === 'react') {
1133
+ return 'let'
1134
+ }
1135
+ return 'var'
1136
+ }
1137
+ if (lower === 'soit' || lower === 'let') {
1138
+ return 'let'
1139
+ }
1140
+
1141
+ return 'let'
1142
+ }
1143
+
1144
+ parseFunctionDeclaration(lang) {
1145
+ this.advance()
1146
+
1147
+ const nameToken = this.current()
1148
+ if (!nameToken || nameToken.type !== TokenType.IDENTIFIER) {
1149
+ return null
1150
+ }
1151
+ const name = nameToken.value
1152
+ this.advance()
1153
+
1154
+ const params = []
1155
+ if (this.match(TokenType.LPAREN)) {
1156
+ while (!this.isAtEnd() && !this.match(TokenType.RPAREN)) {
1157
+ const param = this.parseParameter(lang)
1158
+ if (param) {
1159
+ params.push(param)
1160
+ }
1161
+ this.match(TokenType.COMMA)
1162
+ }
1163
+ } else {
1164
+ while (!this.isAtEnd()) {
1165
+ const token = this.current()
1166
+ if (!token || token.type === TokenType.NEWLINE || token.type === TokenType.COLON || token.type === TokenType.ARROW) {
1167
+ break
1168
+ }
1169
+ if (token.type === TokenType.IDENTIFIER) {
1170
+ const param = this.parseParameter(lang)
1171
+ if (param) {
1172
+ params.push(param)
1173
+ }
1174
+ } else {
1175
+ break
1176
+ }
1177
+ this.match(TokenType.COMMA)
1178
+ }
1179
+ }
1180
+
1181
+ let returnType = null
1182
+ if (this.match(TokenType.COLON) || this.match(TokenType.ARROW)) {
1183
+ returnType = this.parseType(lang)
1184
+ }
1185
+
1186
+ this.skipNewlines()
1187
+ const body = this.parseBlock(lang)
1188
+
1189
+ return {
1190
+ type: 'FunctionDeclaration',
1191
+ name: name,
1192
+ params: params,
1193
+ returnType: returnType,
1194
+ body: body
1195
+ }
1196
+ }
1197
+
1198
+ parseParameter(lang) {
1199
+ const nameToken = this.current()
1200
+ if (!nameToken || nameToken.type !== TokenType.IDENTIFIER) {
1201
+ return null
1202
+ }
1203
+ const name = nameToken.value
1204
+ this.advance()
1205
+
1206
+ let typeAnnotation = null
1207
+ if (this.match(TokenType.COLON)) {
1208
+ typeAnnotation = this.parseType(lang)
1209
+ }
1210
+
1211
+ let defaultValue = null
1212
+ if (this.match(TokenType.EQUALS)) {
1213
+ defaultValue = this.parseExpression(lang)
1214
+ }
1215
+
1216
+ return {
1217
+ type: 'Parameter',
1218
+ name: name,
1219
+ typeAnnotation: typeAnnotation,
1220
+ default: defaultValue
1221
+ }
1222
+ }
1223
+
1224
+ parseType(lang) {
1225
+ const token = this.current()
1226
+ if (!token) return null
1227
+
1228
+ const typeName = this.translateType(token.value, lang)
1229
+ this.advance()
1230
+
1231
+ let generic = null
1232
+ if (this.match(TokenType.LT)) {
1233
+ generic = []
1234
+ while (!this.isAtEnd() && !this.match(TokenType.GT)) {
1235
+ const innerType = this.parseType(lang)
1236
+ if (innerType) {
1237
+ generic.push(innerType)
1238
+ }
1239
+ this.match(TokenType.COMMA)
1240
+ }
1241
+ }
1242
+
1243
+ let isArray = false
1244
+ if (this.match(TokenType.LBRACKET)) {
1245
+ this.match(TokenType.RBRACKET)
1246
+ isArray = true
1247
+ }
1248
+
1249
+ return {
1250
+ type: 'TypeAnnotation',
1251
+ name: typeName,
1252
+ generic: generic,
1253
+ isArray: isArray
1254
+ }
1255
+ }
1256
+
1257
+ translateType(value, lang) {
1258
+ const lower = value.toLowerCase()
1259
+
1260
+ const types = {
1261
+ 'chaine': 'string',
1262
+ 'texte': 'string',
1263
+ 'nombre': 'number',
1264
+ 'entier': lang === 'ts' ? 'number' : 'int',
1265
+ 'decimal': lang === 'ts' ? 'number' : 'float',
1266
+ 'flottant': lang === 'ts' ? 'number' : 'float',
1267
+ 'booleen': 'boolean',
1268
+ 'bool': 'boolean',
1269
+ 'vrai faux': 'boolean',
1270
+ 'tableau': 'Array',
1271
+ 'liste': lang === 'python' ? 'list' : 'Array',
1272
+ 'objet': 'object',
1273
+ 'dictionnaire': lang === 'python' ? 'dict' : 'object',
1274
+ 'nul': 'null',
1275
+ 'rien': 'void',
1276
+ 'vide': 'void',
1277
+ 'indefini': 'undefined',
1278
+ 'quelconque': 'any',
1279
+ 'jamais': 'never',
1280
+ 'inconnu': 'unknown',
1281
+ 'symbole': 'symbol',
1282
+ 'date': 'Date',
1283
+ 'promesse': 'Promise',
1284
+ 'fonction': 'Function'
1285
+ }
1286
+
1287
+ return types[lower] || value
1288
+ }
1289
+
1290
+ parseClassDeclaration(lang) {
1291
+ this.advance()
1292
+
1293
+ const nameToken = this.current()
1294
+ if (!nameToken || nameToken.type !== TokenType.IDENTIFIER) {
1295
+ return null
1296
+ }
1297
+ const name = nameToken.value
1298
+ this.advance()
1299
+
1300
+ let extends_ = null
1301
+ if (this.matchValue('etend') || this.matchValue('herite') || this.matchValue('extends')) {
1302
+ const parentToken = this.current()
1303
+ if (parentToken) {
1304
+ extends_ = parentToken.value
1305
+ this.advance()
1306
+ }
1307
+ }
1308
+
1309
+ let implements_ = []
1310
+ if (this.matchValue('implemente') || this.matchValue('implements')) {
1311
+ while (!this.isAtEnd()) {
1312
+ const implToken = this.current()
1313
+ if (!implToken || implToken.type !== TokenType.IDENTIFIER) break
1314
+ implements_.push(implToken.value)
1315
+ this.advance()
1316
+ if (!this.match(TokenType.COMMA)) break
1317
+ }
1318
+ }
1319
+
1320
+ this.skipNewlines()
1321
+ const body = this.parseBlock(lang)
1322
+
1323
+ return {
1324
+ type: 'ClassDeclaration',
1325
+ name: name,
1326
+ extends: extends_,
1327
+ implements: implements_,
1328
+ body: body
1329
+ }
1330
+ }
1331
+
1332
+ parseConditional(lang) {
1333
+ const keyword = this.advance()
1334
+ const condition = this.parseExpression(lang)
1335
+
1336
+ this.skipNewlines()
1337
+ const consequent = this.parseBlock(lang)
1338
+
1339
+ let alternate = null
1340
+ this.skipNewlines()
1341
+
1342
+ if (this.matchValue('sinon')) {
1343
+ if (this.matchValue('si')) {
1344
+ alternate = this.parseConditional(lang)
1345
+ } else {
1346
+ this.skipNewlines()
1347
+ alternate = this.parseBlock(lang)
1348
+ }
1349
+ }
1350
+
1351
+ return {
1352
+ type: 'IfStatement',
1353
+ condition: condition,
1354
+ consequent: consequent,
1355
+ alternate: alternate
1356
+ }
1357
+ }
1358
+
1359
+ parseLoop(lang) {
1360
+ const keyword = this.advance()
1361
+ const keywordValue = keyword.value.toLowerCase()
1362
+
1363
+ if (keywordValue === 'pour' || keywordValue === 'for' || keywordValue === 'pour chaque' || keywordValue === 'chaque') {
1364
+ return this.parseForLoop(lang)
1365
+ }
1366
+
1367
+ if (keywordValue === 'tant que' || keywordValue === 'while') {
1368
+ return this.parseWhileLoop(lang)
1369
+ }
1370
+
1371
+ if (keywordValue === 'faire' || keywordValue === 'do') {
1372
+ return this.parseDoWhileLoop(lang)
1373
+ }
1374
+
1375
+ return this.parseWhileLoop(lang)
1376
+ }
1377
+
1378
+ parseForLoop(lang) {
1379
+ let variable = null
1380
+ let iterable = null
1381
+ let start = null
1382
+ let end = null
1383
+ let step = null
1384
+
1385
+ const varToken = this.current()
1386
+ if (varToken && varToken.type === TokenType.IDENTIFIER) {
1387
+ variable = varToken.value
1388
+ this.advance()
1389
+ }
1390
+
1391
+ if (this.matchValue('dans') || this.matchValue('de') || this.matchValue('in')) {
1392
+ iterable = this.parseExpression(lang)
1393
+ } else if (this.matchValue('de') || this.matchValue('from')) {
1394
+ start = this.parseExpression(lang)
1395
+
1396
+ if (this.matchValue('a') || this.matchValue('jusque') || this.matchValue('to')) {
1397
+ end = this.parseExpression(lang)
1398
+ }
1399
+
1400
+ if (this.matchValue('par') || this.matchValue('step')) {
1401
+ step = this.parseExpression(lang)
1402
+ }
1403
+ }
1404
+
1405
+ this.skipNewlines()
1406
+ const body = this.parseBlock(lang)
1407
+
1408
+ return {
1409
+ type: 'ForStatement',
1410
+ variable: variable,
1411
+ iterable: iterable,
1412
+ start: start,
1413
+ end: end,
1414
+ step: step,
1415
+ body: body
1416
+ }
1417
+ }
1418
+
1419
+ parseWhileLoop(lang) {
1420
+ const condition = this.parseExpression(lang)
1421
+
1422
+ this.skipNewlines()
1423
+ const body = this.parseBlock(lang)
1424
+
1425
+ return {
1426
+ type: 'WhileStatement',
1427
+ condition: condition,
1428
+ body: body
1429
+ }
1430
+ }
1431
+
1432
+ parseDoWhileLoop(lang) {
1433
+ this.skipNewlines()
1434
+ const body = this.parseBlock(lang)
1435
+
1436
+ this.skipNewlines()
1437
+ if (this.matchValue('tant que') || this.matchValue('while')) {
1438
+ const condition = this.parseExpression(lang)
1439
+
1440
+ return {
1441
+ type: 'DoWhileStatement',
1442
+ condition: condition,
1443
+ body: body
1444
+ }
1445
+ }
1446
+
1447
+ return {
1448
+ type: 'DoWhileStatement',
1449
+ condition: { type: 'Literal', value: true },
1450
+ body: body
1451
+ }
1452
+ }
1453
+
1454
+ parseReturn(lang) {
1455
+ this.advance()
1456
+
1457
+ const value = this.parseExpression(lang)
1458
+
1459
+ return {
1460
+ type: 'ReturnStatement',
1461
+ value: value
1462
+ }
1463
+ }
1464
+
1465
+ parseImport(lang) {
1466
+ this.advance()
1467
+
1468
+ const imports = []
1469
+ let source = null
1470
+ let defaultImport = null
1471
+
1472
+ const token = this.current()
1473
+
1474
+ if (token && token.type === TokenType.LBRACE) {
1475
+ this.advance()
1476
+ while (!this.isAtEnd() && !this.match(TokenType.RBRACE)) {
1477
+ const nameToken = this.current()
1478
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
1479
+ let imported = nameToken.value
1480
+ let local = imported
1481
+ this.advance()
1482
+
1483
+ if (this.matchValue('comme') || this.matchValue('as')) {
1484
+ const aliasToken = this.current()
1485
+ if (aliasToken && aliasToken.type === TokenType.IDENTIFIER) {
1486
+ local = aliasToken.value
1487
+ this.advance()
1488
+ }
1489
+ }
1490
+
1491
+ imports.push({ imported, local })
1492
+ }
1493
+ this.match(TokenType.COMMA)
1494
+ }
1495
+ } else if (token && token.type === TokenType.IDENTIFIER) {
1496
+ defaultImport = token.value
1497
+ this.advance()
1498
+ }
1499
+
1500
+ if (this.matchValue('depuis') || this.matchValue('de') || this.matchValue('from')) {
1501
+ const sourceToken = this.current()
1502
+ if (sourceToken && sourceToken.type === TokenType.STRING) {
1503
+ source = sourceToken.value.replace(/^["']|["']$/g, '')
1504
+ this.advance()
1505
+ }
1506
+ }
1507
+
1508
+ return {
1509
+ type: 'ImportDeclaration',
1510
+ imports: imports,
1511
+ defaultImport: defaultImport,
1512
+ source: source
1513
+ }
1514
+ }
1515
+
1516
+ parseExport(lang) {
1517
+ this.advance()
1518
+
1519
+ let isDefault = false
1520
+ if (this.matchValue('defaut') || this.matchValue('default')) {
1521
+ isDefault = true
1522
+ }
1523
+
1524
+ const declaration = this.parseStatement(lang)
1525
+
1526
+ return {
1527
+ type: 'ExportDeclaration',
1528
+ isDefault: isDefault,
1529
+ declaration: declaration
1530
+ }
1531
+ }
1532
+
1533
+ parseBlock(lang) {
1534
+ const body = []
1535
+
1536
+ if (this.match(TokenType.INDENT)) {
1537
+ while (!this.isAtEnd()) {
1538
+ const current = this.current()
1539
+
1540
+ if (current && current.type === TokenType.DEDENT) {
1541
+ this.advance()
1542
+ break
1543
+ }
1544
+
1545
+ const statement = this.parseStatement(lang)
1546
+ if (statement) {
1547
+ body.push(statement)
1548
+ }
1549
+
1550
+ this.skipNewlines()
1551
+ }
1552
+ }
1553
+
1554
+ return {
1555
+ type: 'BlockStatement',
1556
+ body: body
1557
+ }
1558
+ }
1559
+
1560
+ parseExpression(lang) {
1561
+ return this.parseAssignment(lang)
1562
+ }
1563
+
1564
+ parseAssignment(lang) {
1565
+ const left = this.parseLogicalOr(lang)
1566
+
1567
+ if (this.match(TokenType.EQUALS)) {
1568
+ const right = this.parseAssignment(lang)
1569
+ return {
1570
+ type: 'AssignmentExpression',
1571
+ operator: '=',
1572
+ left: left,
1573
+ right: right
1574
+ }
1575
+ }
1576
+
1577
+ return left
1578
+ }
1579
+
1580
+ parseLogicalOr(lang) {
1581
+ let left = this.parseLogicalAnd(lang)
1582
+
1583
+ while (this.match(TokenType.DOUBLE_PIPE) || this.matchValue('ou')) {
1584
+ const right = this.parseLogicalAnd(lang)
1585
+ left = {
1586
+ type: 'BinaryExpression',
1587
+ operator: '||',
1588
+ left: left,
1589
+ right: right
1590
+ }
1591
+ }
1592
+
1593
+ return left
1594
+ }
1595
+
1596
+ parseLogicalAnd(lang) {
1597
+ let left = this.parseEquality(lang)
1598
+
1599
+ while (this.match(TokenType.DOUBLE_AMPERSAND) || this.matchValue('et')) {
1600
+ const right = this.parseEquality(lang)
1601
+ left = {
1602
+ type: 'BinaryExpression',
1603
+ operator: '&&',
1604
+ left: left,
1605
+ right: right
1606
+ }
1607
+ }
1608
+
1609
+ return left
1610
+ }
1611
+
1612
+ parseEquality(lang) {
1613
+ let left = this.parseComparison(lang)
1614
+
1615
+ while (true) {
1616
+ if (this.match(TokenType.DOUBLE_EQUALS) || this.matchValue('egal') || this.matchValue('egale')) {
1617
+ const right = this.parseComparison(lang)
1618
+ left = { type: 'BinaryExpression', operator: '===', left, right }
1619
+ } else if (this.match(TokenType.NOT_EQUALS) || this.matchValue('different')) {
1620
+ const right = this.parseComparison(lang)
1621
+ left = { type: 'BinaryExpression', operator: '!==', left, right }
1622
+ } else {
1623
+ break
1624
+ }
1625
+ }
1626
+
1627
+ return left
1628
+ }
1629
+
1630
+ parseComparison(lang) {
1631
+ let left = this.parseAdditive(lang)
1632
+
1633
+ while (true) {
1634
+ if (this.match(TokenType.LT) || this.matchValue('inferieur')) {
1635
+ const right = this.parseAdditive(lang)
1636
+ left = { type: 'BinaryExpression', operator: '<', left, right }
1637
+ } else if (this.match(TokenType.GT) || this.matchValue('superieur')) {
1638
+ const right = this.parseAdditive(lang)
1639
+ left = { type: 'BinaryExpression', operator: '>', left, right }
1640
+ } else if (this.match(TokenType.LTE) || this.matchValue('inferieur ou egal')) {
1641
+ const right = this.parseAdditive(lang)
1642
+ left = { type: 'BinaryExpression', operator: '<=', left, right }
1643
+ } else if (this.match(TokenType.GTE) || this.matchValue('superieur ou egal')) {
1644
+ const right = this.parseAdditive(lang)
1645
+ left = { type: 'BinaryExpression', operator: '>=', left, right }
1646
+ } else {
1647
+ break
1648
+ }
1649
+ }
1650
+
1651
+ return left
1652
+ }
1653
+
1654
+ parseAdditive(lang) {
1655
+ let left = this.parseMultiplicative(lang)
1656
+
1657
+ while (true) {
1658
+ if (this.match(TokenType.PLUS) || this.matchValue('plus')) {
1659
+ const right = this.parseMultiplicative(lang)
1660
+ left = { type: 'BinaryExpression', operator: '+', left, right }
1661
+ } else if (this.match(TokenType.MINUS) || this.matchValue('moins')) {
1662
+ const right = this.parseMultiplicative(lang)
1663
+ left = { type: 'BinaryExpression', operator: '-', left, right }
1664
+ } else {
1665
+ break
1666
+ }
1667
+ }
1668
+
1669
+ return left
1670
+ }
1671
+
1672
+ parseMultiplicative(lang) {
1673
+ let left = this.parseUnary(lang)
1674
+
1675
+ while (true) {
1676
+ if (this.match(TokenType.STAR) || this.matchValue('fois') || this.matchValue('multiplie')) {
1677
+ const right = this.parseUnary(lang)
1678
+ left = { type: 'BinaryExpression', operator: '*', left, right }
1679
+ } else if (this.match(TokenType.SLASH) || this.matchValue('divise')) {
1680
+ const right = this.parseUnary(lang)
1681
+ left = { type: 'BinaryExpression', operator: '/', left, right }
1682
+ } else if (this.match(TokenType.PERCENT) || this.matchValue('modulo')) {
1683
+ const right = this.parseUnary(lang)
1684
+ left = { type: 'BinaryExpression', operator: '%', left, right }
1685
+ } else {
1686
+ break
1687
+ }
1688
+ }
1689
+
1690
+ return left
1691
+ }
1692
+
1693
+ parseUnary(lang) {
1694
+ if (this.match(TokenType.BANG) || this.matchValue('non') || this.matchValue('pas')) {
1695
+ const operand = this.parseUnary(lang)
1696
+ return { type: 'UnaryExpression', operator: '!', operand }
1697
+ }
1698
+
1699
+ if (this.match(TokenType.MINUS)) {
1700
+ const operand = this.parseUnary(lang)
1701
+ return { type: 'UnaryExpression', operator: '-', operand }
1702
+ }
1703
+
1704
+ return this.parseCall(lang)
1705
+ }
1706
+
1707
+ parseCall(lang) {
1708
+ let expr = this.parsePrimary(lang)
1709
+
1710
+ while (true) {
1711
+ if (this.match(TokenType.LPAREN)) {
1712
+ const args = []
1713
+ while (!this.isAtEnd() && !this.match(TokenType.RPAREN)) {
1714
+ args.push(this.parseExpression(lang))
1715
+ this.match(TokenType.COMMA)
1716
+ }
1717
+ expr = { type: 'CallExpression', callee: expr, arguments: args }
1718
+ } else if (this.match(TokenType.DOT)) {
1719
+ const property = this.current()
1720
+ if (property && property.type === TokenType.IDENTIFIER) {
1721
+ this.advance()
1722
+ expr = { type: 'MemberExpression', object: expr, property: property.value }
1723
+ }
1724
+ } else if (this.match(TokenType.LBRACKET)) {
1725
+ const index = this.parseExpression(lang)
1726
+ this.expect(TokenType.RBRACKET)
1727
+ expr = { type: 'IndexExpression', object: expr, index }
1728
+ } else {
1729
+ break
1730
+ }
1731
+ }
1732
+
1733
+ return expr
1734
+ }
1735
+
1736
+ parsePrimary(lang) {
1737
+ const token = this.current()
1738
+
1739
+ if (!token) {
1740
+ return { type: 'Literal', value: null }
1741
+ }
1742
+
1743
+ if (token.type === TokenType.NUMBER || token.type === TokenType.INTEGER || token.type === TokenType.FLOAT) {
1744
+ this.advance()
1745
+ return { type: 'Literal', value: parseFloat(token.value) }
1746
+ }
1747
+
1748
+ if (token.type === TokenType.STRING) {
1749
+ this.advance()
1750
+ return { type: 'Literal', value: token.value.replace(/^["']|["']$/g, '') }
1751
+ }
1752
+
1753
+ if (token.type === TokenType.IDENTIFIER) {
1754
+ const value = token.value.toLowerCase()
1755
+
1756
+ if (value === 'vrai' || value === 'true') {
1757
+ this.advance()
1758
+ return { type: 'Literal', value: true }
1759
+ }
1760
+
1761
+ if (value === 'faux' || value === 'false') {
1762
+ this.advance()
1763
+ return { type: 'Literal', value: false }
1764
+ }
1765
+
1766
+ if (value === 'nul' || value === 'null' || value === 'rien') {
1767
+ this.advance()
1768
+ return { type: 'Literal', value: null }
1769
+ }
1770
+
1771
+ if (value === 'indefini' || value === 'undefined') {
1772
+ this.advance()
1773
+ return { type: 'Literal', value: undefined }
1774
+ }
1775
+
1776
+ this.advance()
1777
+ return { type: 'Identifier', name: token.value }
1778
+ }
1779
+
1780
+ if (token.type === TokenType.LBRACKET) {
1781
+ return this.parseArrayLiteral(lang)
1782
+ }
1783
+
1784
+ if (token.type === TokenType.LBRACE) {
1785
+ return this.parseObjectLiteral(lang)
1786
+ }
1787
+
1788
+ if (token.type === TokenType.LPAREN) {
1789
+ this.advance()
1790
+ const expr = this.parseExpression(lang)
1791
+ this.expect(TokenType.RPAREN)
1792
+ return expr
1793
+ }
1794
+
1795
+ this.advance()
1796
+ return { type: 'Literal', value: null }
1797
+ }
1798
+
1799
+ parseArrayLiteral(lang) {
1800
+ this.expect(TokenType.LBRACKET)
1801
+ const elements = []
1802
+
1803
+ while (!this.isAtEnd() && !this.match(TokenType.RBRACKET)) {
1804
+ elements.push(this.parseExpression(lang))
1805
+ this.match(TokenType.COMMA)
1806
+ }
1807
+
1808
+ return { type: 'ArrayLiteral', elements }
1809
+ }
1810
+
1811
+ parseObjectLiteral(lang) {
1812
+ this.expect(TokenType.LBRACE)
1813
+ const properties = []
1814
+
1815
+ while (!this.isAtEnd() && !this.match(TokenType.RBRACE)) {
1816
+ const keyToken = this.current()
1817
+ if (!keyToken) break
1818
+
1819
+ let key
1820
+ if (keyToken.type === TokenType.STRING) {
1821
+ key = keyToken.value.replace(/^["']|["']$/g, '')
1822
+ } else if (keyToken.type === TokenType.IDENTIFIER) {
1823
+ key = keyToken.value
1824
+ } else {
1825
+ break
1826
+ }
1827
+ this.advance()
1828
+
1829
+ this.match(TokenType.COLON) || this.match(TokenType.EQUALS)
1830
+
1831
+ const value = this.parseExpression(lang)
1832
+ properties.push({ key, value })
1833
+
1834
+ this.match(TokenType.COMMA)
1835
+ }
1836
+
1837
+ return { type: 'ObjectLiteral', properties }
1838
+ }
1839
+
1840
+ parseSQLProgram() {
1841
+ const program = {
1842
+ type: 'SQLProgram',
1843
+ statements: []
1844
+ }
1845
+
1846
+ this.skipNewlines()
1847
+
1848
+ while (!this.isAtEnd()) {
1849
+ const statement = this.parseSQLStatement()
1850
+ if (statement) {
1851
+ program.statements.push(statement)
1852
+ }
1853
+ this.skipNewlines()
1854
+ }
1855
+
1856
+ return program
1857
+ }
1858
+
1859
+ parseSQLStatement() {
1860
+ this.skipNewlines()
1861
+ const token = this.current()
1862
+
1863
+ if (!token || token.type === TokenType.EOF) return null
1864
+
1865
+ const value = token.value ? token.value.toLowerCase() : ''
1866
+
1867
+ if (value === 'selectionner' || value === 'select' || value === 'choisir') {
1868
+ return this.parseSQLSelect()
1869
+ }
1870
+
1871
+ if (value === 'inserer' || value === 'insert' || value === 'ajouter') {
1872
+ return this.parseSQLInsert()
1873
+ }
1874
+
1875
+ if (value === 'mettre' || value === 'update' || value === 'modifier') {
1876
+ return this.parseSQLUpdate()
1877
+ }
1878
+
1879
+ if (value === 'supprimer' || value === 'delete' || value === 'effacer') {
1880
+ return this.parseSQLDelete()
1881
+ }
1882
+
1883
+ if (value === 'creer' || value === 'create') {
1884
+ return this.parseSQLCreate()
1885
+ }
1886
+
1887
+ if (value === 'detruire' || value === 'drop') {
1888
+ return this.parseSQLDrop()
1889
+ }
1890
+
1891
+ if (value === 'modifier' || value === 'alter') {
1892
+ return this.parseSQLAlter()
1893
+ }
1894
+
1895
+ this.advance()
1896
+ return null
1897
+ }
1898
+
1899
+ parseSQLSelect() {
1900
+ this.advance()
1901
+
1902
+ const columns = []
1903
+
1904
+ while (!this.isAtEnd()) {
1905
+ const token = this.current()
1906
+
1907
+ if (!token || token.type === TokenType.EOF) break
1908
+
1909
+ const value = token.value ? token.value.toLowerCase() : ''
1910
+ if (value === 'depuis' || value === 'de' || value === 'from') break
1911
+
1912
+ if (token.type === TokenType.STAR) {
1913
+ columns.push('*')
1914
+ this.advance()
1915
+ } else if (token.type === TokenType.IDENTIFIER) {
1916
+ columns.push(token.value)
1917
+ this.advance()
1918
+ } else if (token.type === TokenType.COMMA) {
1919
+ this.advance()
1920
+ } else {
1921
+ break
1922
+ }
1923
+ }
1924
+
1925
+ let table = null
1926
+ if (this.matchValue('depuis') || this.matchValue('de') || this.matchValue('from')) {
1927
+ const tableToken = this.current()
1928
+ if (tableToken && tableToken.type === TokenType.IDENTIFIER) {
1929
+ table = tableToken.value
1930
+ this.advance()
1931
+ }
1932
+ }
1933
+
1934
+ let where = null
1935
+ if (this.matchValue('ou') || this.matchValue('where')) {
1936
+ where = this.parseSQLWhere()
1937
+ }
1938
+
1939
+ let orderBy = null
1940
+ if (this.matchValue('trier') || this.matchValue('ordonner') || this.matchValue('order')) {
1941
+ if (this.matchValue('par') || this.matchValue('by')) {
1942
+ orderBy = this.parseSQLOrderBy()
1943
+ }
1944
+ }
1945
+
1946
+ let limit = null
1947
+ if (this.matchValue('limiter') || this.matchValue('limit')) {
1948
+ const limitToken = this.current()
1949
+ if (limitToken && (limitToken.type === TokenType.NUMBER || limitToken.type === TokenType.INTEGER)) {
1950
+ limit = parseInt(limitToken.value)
1951
+ this.advance()
1952
+ }
1953
+ }
1954
+
1955
+ return {
1956
+ type: 'SelectStatement',
1957
+ columns: columns,
1958
+ table: table,
1959
+ where: where,
1960
+ orderBy: orderBy,
1961
+ limit: limit
1962
+ }
1963
+ }
1964
+
1965
+ parseSQLWhere() {
1966
+ const conditions = []
1967
+
1968
+ while (!this.isAtEnd()) {
1969
+ const token = this.current()
1970
+
1971
+ if (!token || token.type === TokenType.EOF) break
1972
+
1973
+ const value = token.value ? token.value.toLowerCase() : ''
1974
+ if (value === 'trier' || value === 'ordonner' || value === 'order' ||
1975
+ value === 'limiter' || value === 'limit' || value === 'grouper') break
1976
+
1977
+ if (token.type === TokenType.IDENTIFIER) {
1978
+ const field = token.value
1979
+ this.advance()
1980
+
1981
+ const opToken = this.current()
1982
+ let operator = '='
1983
+
1984
+ if (opToken) {
1985
+ if (opToken.type === TokenType.EQUALS || opToken.type === TokenType.DOUBLE_EQUALS) {
1986
+ operator = '='
1987
+ this.advance()
1988
+ } else if (opToken.type === TokenType.NOT_EQUALS) {
1989
+ operator = '<>'
1990
+ this.advance()
1991
+ } else if (opToken.type === TokenType.LT) {
1992
+ operator = '<'
1993
+ this.advance()
1994
+ } else if (opToken.type === TokenType.GT) {
1995
+ operator = '>'
1996
+ this.advance()
1997
+ } else if (opToken.type === TokenType.LTE) {
1998
+ operator = '<='
1999
+ this.advance()
2000
+ } else if (opToken.type === TokenType.GTE) {
2001
+ operator = '>='
2002
+ this.advance()
2003
+ } else if (opToken.value && opToken.value.toLowerCase() === 'egal') {
2004
+ operator = '='
2005
+ this.advance()
2006
+ }
2007
+ }
2008
+
2009
+ const valueToken = this.current()
2010
+ let condValue = null
2011
+
2012
+ if (valueToken) {
2013
+ if (valueToken.type === TokenType.STRING) {
2014
+ condValue = valueToken.value
2015
+ } else if (valueToken.type === TokenType.NUMBER || valueToken.type === TokenType.INTEGER) {
2016
+ condValue = parseFloat(valueToken.value)
2017
+ } else if (valueToken.type === TokenType.IDENTIFIER) {
2018
+ condValue = valueToken.value
2019
+ }
2020
+ this.advance()
2021
+ }
2022
+
2023
+ conditions.push({ field, operator, value: condValue })
2024
+ } else if (value === 'et' || value === 'and') {
2025
+ conditions.push({ type: 'AND' })
2026
+ this.advance()
2027
+ } else if (value === 'ou' || value === 'or') {
2028
+ conditions.push({ type: 'OR' })
2029
+ this.advance()
2030
+ } else {
2031
+ this.advance()
2032
+ }
2033
+ }
2034
+
2035
+ return conditions
2036
+ }
2037
+
2038
+ parseSQLOrderBy() {
2039
+ const orders = []
2040
+
2041
+ while (!this.isAtEnd()) {
2042
+ const token = this.current()
2043
+
2044
+ if (!token || token.type === TokenType.EOF) break
2045
+
2046
+ const value = token.value ? token.value.toLowerCase() : ''
2047
+ if (value === 'limiter' || value === 'limit' || value === 'grouper') break
2048
+
2049
+ if (token.type === TokenType.IDENTIFIER) {
2050
+ const field = token.value
2051
+ this.advance()
2052
+
2053
+ let direction = 'ASC'
2054
+ const dirToken = this.current()
2055
+
2056
+ if (dirToken) {
2057
+ const dirValue = dirToken.value ? dirToken.value.toLowerCase() : ''
2058
+ if (dirValue === 'desc' || dirValue === 'descendant' || dirValue === 'decroissant') {
2059
+ direction = 'DESC'
2060
+ this.advance()
2061
+ } else if (dirValue === 'asc' || dirValue === 'ascendant' || dirValue === 'croissant') {
2062
+ direction = 'ASC'
2063
+ this.advance()
2064
+ }
2065
+ }
2066
+
2067
+ orders.push({ field, direction })
2068
+ } else if (token.type === TokenType.COMMA) {
2069
+ this.advance()
2070
+ } else {
2071
+ break
2072
+ }
2073
+ }
2074
+
2075
+ return orders
2076
+ }
2077
+
2078
+ parseSQLInsert() {
2079
+ this.advance()
2080
+
2081
+ if (this.matchValue('dans') || this.matchValue('into') || this.matchValue('in')) {
2082
+ }
2083
+
2084
+ const tableToken = this.current()
2085
+ let table = null
2086
+ if (tableToken && tableToken.type === TokenType.IDENTIFIER) {
2087
+ table = tableToken.value
2088
+ this.advance()
2089
+ }
2090
+
2091
+ const columns = []
2092
+ if (this.match(TokenType.LPAREN)) {
2093
+ while (!this.isAtEnd() && !this.match(TokenType.RPAREN)) {
2094
+ const colToken = this.current()
2095
+ if (colToken && colToken.type === TokenType.IDENTIFIER) {
2096
+ columns.push(colToken.value)
2097
+ this.advance()
2098
+ }
2099
+ this.match(TokenType.COMMA)
2100
+ }
2101
+ }
2102
+
2103
+ const values = []
2104
+ if (this.matchValue('valeurs') || this.matchValue('values')) {
2105
+ if (this.match(TokenType.LPAREN)) {
2106
+ while (!this.isAtEnd() && !this.match(TokenType.RPAREN)) {
2107
+ const valToken = this.current()
2108
+ if (valToken) {
2109
+ if (valToken.type === TokenType.STRING) {
2110
+ values.push(valToken.value)
2111
+ } else if (valToken.type === TokenType.NUMBER || valToken.type === TokenType.INTEGER) {
2112
+ values.push(parseFloat(valToken.value))
2113
+ } else if (valToken.type === TokenType.IDENTIFIER) {
2114
+ const v = valToken.value.toLowerCase()
2115
+ if (v === 'vrai' || v === 'true') values.push(true)
2116
+ else if (v === 'faux' || v === 'false') values.push(false)
2117
+ else if (v === 'nul' || v === 'null') values.push(null)
2118
+ else values.push(valToken.value)
2119
+ }
2120
+ this.advance()
2121
+ }
2122
+ this.match(TokenType.COMMA)
2123
+ }
2124
+ }
2125
+ }
2126
+
2127
+ return {
2128
+ type: 'InsertStatement',
2129
+ table: table,
2130
+ columns: columns,
2131
+ values: values
2132
+ }
2133
+ }
2134
+
2135
+ parseSQLUpdate() {
2136
+ this.advance()
2137
+
2138
+ if (this.matchValue('a jour') || this.matchValue('jour')) {
2139
+ }
2140
+
2141
+ const tableToken = this.current()
2142
+ let table = null
2143
+ if (tableToken && tableToken.type === TokenType.IDENTIFIER) {
2144
+ table = tableToken.value
2145
+ this.advance()
2146
+ }
2147
+
2148
+ const assignments = []
2149
+ if (this.matchValue('definir') || this.matchValue('set') || this.matchValue('avec')) {
2150
+ while (!this.isAtEnd()) {
2151
+ const colToken = this.current()
2152
+
2153
+ if (!colToken || colToken.type === TokenType.EOF) break
2154
+
2155
+ const value = colToken.value ? colToken.value.toLowerCase() : ''
2156
+ if (value === 'ou' || value === 'where') break
2157
+
2158
+ if (colToken.type === TokenType.IDENTIFIER) {
2159
+ const column = colToken.value
2160
+ this.advance()
2161
+
2162
+ if (this.match(TokenType.EQUALS) || this.match(TokenType.COLON)) {
2163
+ const valToken = this.current()
2164
+ let val = null
2165
+
2166
+ if (valToken) {
2167
+ if (valToken.type === TokenType.STRING) {
2168
+ val = valToken.value
2169
+ } else if (valToken.type === TokenType.NUMBER || valToken.type === TokenType.INTEGER) {
2170
+ val = parseFloat(valToken.value)
2171
+ } else if (valToken.type === TokenType.IDENTIFIER) {
2172
+ val = valToken.value
2173
+ }
2174
+ this.advance()
2175
+ }
2176
+
2177
+ assignments.push({ column, value: val })
2178
+ }
2179
+ }
2180
+
2181
+ this.match(TokenType.COMMA)
2182
+ }
2183
+ }
2184
+
2185
+ let where = null
2186
+ if (this.matchValue('ou') || this.matchValue('where')) {
2187
+ where = this.parseSQLWhere()
2188
+ }
2189
+
2190
+ return {
2191
+ type: 'UpdateStatement',
2192
+ table: table,
2193
+ assignments: assignments,
2194
+ where: where
2195
+ }
2196
+ }
2197
+
2198
+ parseSQLDelete() {
2199
+ this.advance()
2200
+
2201
+ if (this.matchValue('de') || this.matchValue('depuis') || this.matchValue('from')) {
2202
+ }
2203
+
2204
+ const tableToken = this.current()
2205
+ let table = null
2206
+ if (tableToken && tableToken.type === TokenType.IDENTIFIER) {
2207
+ table = tableToken.value
2208
+ this.advance()
2209
+ }
2210
+
2211
+ let where = null
2212
+ if (this.matchValue('ou') || this.matchValue('where')) {
2213
+ where = this.parseSQLWhere()
2214
+ }
2215
+
2216
+ return {
2217
+ type: 'DeleteStatement',
2218
+ table: table,
2219
+ where: where
2220
+ }
2221
+ }
2222
+
2223
+ parseSQLCreate() {
2224
+ this.advance()
2225
+
2226
+ if (this.matchValue('table')) {
2227
+ return this.parseSQLCreateTable()
2228
+ }
2229
+
2230
+ if (this.matchValue('base') || this.matchValue('database')) {
2231
+ this.matchValue('de')
2232
+ this.matchValue('donnees')
2233
+ return this.parseSQLCreateDatabase()
2234
+ }
2235
+
2236
+ if (this.matchValue('index')) {
2237
+ return this.parseSQLCreateIndex()
2238
+ }
2239
+
2240
+ return null
2241
+ }
2242
+
2243
+ parseSQLCreateTable() {
2244
+ const nameToken = this.current()
2245
+ let name = null
2246
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2247
+ name = nameToken.value
2248
+ this.advance()
2249
+ }
2250
+
2251
+ const columns = []
2252
+
2253
+ if (this.match(TokenType.LPAREN)) {
2254
+ while (!this.isAtEnd() && !this.match(TokenType.RPAREN)) {
2255
+ const col = this.parseSQLColumnDef()
2256
+ if (col) {
2257
+ columns.push(col)
2258
+ }
2259
+ this.match(TokenType.COMMA)
2260
+ }
2261
+ } else {
2262
+ this.skipNewlines()
2263
+ this.match(TokenType.INDENT)
2264
+
2265
+ while (!this.isAtEnd()) {
2266
+ const current = this.current()
2267
+
2268
+ if (current && current.type === TokenType.DEDENT) {
2269
+ this.advance()
2270
+ break
2271
+ }
2272
+
2273
+ if (current && current.type === TokenType.NEWLINE) {
2274
+ this.advance()
2275
+ continue
2276
+ }
2277
+
2278
+ const col = this.parseSQLColumnDef()
2279
+ if (col) {
2280
+ columns.push(col)
2281
+ }
2282
+ }
2283
+ }
2284
+
2285
+ return {
2286
+ type: 'CreateTableStatement',
2287
+ name: name,
2288
+ columns: columns
2289
+ }
2290
+ }
2291
+
2292
+ parseSQLColumnDef() {
2293
+ const nameToken = this.current()
2294
+ if (!nameToken || nameToken.type !== TokenType.IDENTIFIER) {
2295
+ return null
2296
+ }
2297
+ const name = nameToken.value
2298
+ this.advance()
2299
+
2300
+ this.match(TokenType.COLON)
2301
+
2302
+ const typeToken = this.current()
2303
+ let dataType = 'TEXT'
2304
+ if (typeToken && typeToken.type === TokenType.IDENTIFIER) {
2305
+ dataType = this.translateSQLType(typeToken.value)
2306
+ this.advance()
2307
+ }
2308
+
2309
+ let size = null
2310
+ if (this.match(TokenType.LPAREN)) {
2311
+ const sizeToken = this.current()
2312
+ if (sizeToken && (sizeToken.type === TokenType.NUMBER || sizeToken.type === TokenType.INTEGER)) {
2313
+ size = parseInt(sizeToken.value)
2314
+ this.advance()
2315
+ }
2316
+ this.match(TokenType.RPAREN)
2317
+ }
2318
+
2319
+ const constraints = []
2320
+
2321
+ while (!this.isAtEnd()) {
2322
+ const token = this.current()
2323
+
2324
+ if (!token || token.type === TokenType.COMMA || token.type === TokenType.RPAREN ||
2325
+ token.type === TokenType.NEWLINE || token.type === TokenType.DEDENT) {
2326
+ break
2327
+ }
2328
+
2329
+ const value = token.value ? token.value.toLowerCase() : ''
2330
+
2331
+ if (value === 'cle' || value === 'key') {
2332
+ this.advance()
2333
+ if (this.matchValue('primaire') || this.matchValue('primary')) {
2334
+ constraints.push('PRIMARY KEY')
2335
+ }
2336
+ } else if (value === 'primaire' || value === 'primary') {
2337
+ this.advance()
2338
+ constraints.push('PRIMARY KEY')
2339
+ } else if (value === 'unique') {
2340
+ this.advance()
2341
+ constraints.push('UNIQUE')
2342
+ } else if (value === 'non' || value === 'not') {
2343
+ this.advance()
2344
+ if (this.matchValue('nul') || this.matchValue('null')) {
2345
+ constraints.push('NOT NULL')
2346
+ }
2347
+ } else if (value === 'auto' || value === 'autoincrement') {
2348
+ this.advance()
2349
+ if (this.matchValue('increment')) {
2350
+ }
2351
+ constraints.push('AUTO_INCREMENT')
2352
+ } else if (value === 'defaut' || value === 'default') {
2353
+ this.advance()
2354
+ const defToken = this.current()
2355
+ if (defToken) {
2356
+ constraints.push(`DEFAULT ${defToken.value}`)
2357
+ this.advance()
2358
+ }
2359
+ } else if (value === 'reference' || value === 'references') {
2360
+ this.advance()
2361
+ const refTable = this.current()
2362
+ if (refTable && refTable.type === TokenType.IDENTIFIER) {
2363
+ let ref = `REFERENCES ${refTable.value}`
2364
+ this.advance()
2365
+ if (this.match(TokenType.LPAREN)) {
2366
+ const refCol = this.current()
2367
+ if (refCol) {
2368
+ ref += `(${refCol.value})`
2369
+ this.advance()
2370
+ }
2371
+ this.match(TokenType.RPAREN)
2372
+ }
2373
+ constraints.push(ref)
2374
+ }
2375
+ } else {
2376
+ this.advance()
2377
+ }
2378
+ }
2379
+
2380
+ return {
2381
+ name: name,
2382
+ type: dataType,
2383
+ size: size,
2384
+ constraints: constraints
2385
+ }
2386
+ }
2387
+
2388
+ translateSQLType(value) {
2389
+ const lower = value.toLowerCase()
2390
+
2391
+ const types = {
2392
+ 'entier': 'INT',
2393
+ 'nombre': 'INT',
2394
+ 'texte': 'TEXT',
2395
+ 'chaine': 'VARCHAR',
2396
+ 'caracteres': 'VARCHAR',
2397
+ 'decimal': 'DECIMAL',
2398
+ 'flottant': 'FLOAT',
2399
+ 'double': 'DOUBLE',
2400
+ 'booleen': 'BOOLEAN',
2401
+ 'date': 'DATE',
2402
+ 'heure': 'TIME',
2403
+ 'horodatage': 'TIMESTAMP',
2404
+ 'dateheure': 'DATETIME',
2405
+ 'blob': 'BLOB',
2406
+ 'binaire': 'BINARY',
2407
+ 'json': 'JSON',
2408
+ 'uuid': 'UUID',
2409
+ 'petit entier': 'SMALLINT',
2410
+ 'grand entier': 'BIGINT',
2411
+ 'tres petit entier': 'TINYINT'
2412
+ }
2413
+
2414
+ return types[lower] || value.toUpperCase()
2415
+ }
2416
+
2417
+ parseSQLCreateDatabase() {
2418
+ const nameToken = this.current()
2419
+ let name = null
2420
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2421
+ name = nameToken.value
2422
+ this.advance()
2423
+ }
2424
+
2425
+ return {
2426
+ type: 'CreateDatabaseStatement',
2427
+ name: name
2428
+ }
2429
+ }
2430
+
2431
+ parseSQLCreateIndex() {
2432
+ let unique = false
2433
+ if (this.matchValue('unique')) {
2434
+ unique = true
2435
+ }
2436
+
2437
+ const nameToken = this.current()
2438
+ let name = null
2439
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2440
+ name = nameToken.value
2441
+ this.advance()
2442
+ }
2443
+
2444
+ if (this.matchValue('sur') || this.matchValue('on')) {
2445
+ }
2446
+
2447
+ const tableToken = this.current()
2448
+ let table = null
2449
+ if (tableToken && tableToken.type === TokenType.IDENTIFIER) {
2450
+ table = tableToken.value
2451
+ this.advance()
2452
+ }
2453
+
2454
+ const columns = []
2455
+ if (this.match(TokenType.LPAREN)) {
2456
+ while (!this.isAtEnd() && !this.match(TokenType.RPAREN)) {
2457
+ const colToken = this.current()
2458
+ if (colToken && colToken.type === TokenType.IDENTIFIER) {
2459
+ columns.push(colToken.value)
2460
+ this.advance()
2461
+ }
2462
+ this.match(TokenType.COMMA)
2463
+ }
2464
+ }
2465
+
2466
+ return {
2467
+ type: 'CreateIndexStatement',
2468
+ name: name,
2469
+ table: table,
2470
+ columns: columns,
2471
+ unique: unique
2472
+ }
2473
+ }
2474
+
2475
+ parseSQLDrop() {
2476
+ this.advance()
2477
+
2478
+ if (this.matchValue('table')) {
2479
+ const nameToken = this.current()
2480
+ let name = null
2481
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2482
+ name = nameToken.value
2483
+ this.advance()
2484
+ }
2485
+ return { type: 'DropTableStatement', name }
2486
+ }
2487
+
2488
+ if (this.matchValue('base') || this.matchValue('database')) {
2489
+ this.matchValue('de')
2490
+ this.matchValue('donnees')
2491
+ const nameToken = this.current()
2492
+ let name = null
2493
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2494
+ name = nameToken.value
2495
+ this.advance()
2496
+ }
2497
+ return { type: 'DropDatabaseStatement', name }
2498
+ }
2499
+
2500
+ if (this.matchValue('index')) {
2501
+ const nameToken = this.current()
2502
+ let name = null
2503
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2504
+ name = nameToken.value
2505
+ this.advance()
2506
+ }
2507
+ return { type: 'DropIndexStatement', name }
2508
+ }
2509
+
2510
+ return null
2511
+ }
2512
+
2513
+ parseSQLAlter() {
2514
+ this.advance()
2515
+
2516
+ if (this.matchValue('table')) {
2517
+ const nameToken = this.current()
2518
+ let name = null
2519
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2520
+ name = nameToken.value
2521
+ this.advance()
2522
+ }
2523
+
2524
+ const actions = []
2525
+
2526
+ if (this.matchValue('ajouter') || this.matchValue('add')) {
2527
+ if (this.matchValue('colonne') || this.matchValue('column')) {
2528
+ }
2529
+ const col = this.parseSQLColumnDef()
2530
+ if (col) {
2531
+ actions.push({ type: 'ADD', column: col })
2532
+ }
2533
+ }
2534
+
2535
+ if (this.matchValue('supprimer') || this.matchValue('drop')) {
2536
+ if (this.matchValue('colonne') || this.matchValue('column')) {
2537
+ }
2538
+ const colToken = this.current()
2539
+ if (colToken && colToken.type === TokenType.IDENTIFIER) {
2540
+ actions.push({ type: 'DROP', column: colToken.value })
2541
+ this.advance()
2542
+ }
2543
+ }
2544
+
2545
+ if (this.matchValue('modifier') || this.matchValue('modify')) {
2546
+ if (this.matchValue('colonne') || this.matchValue('column')) {
2547
+ }
2548
+ const col = this.parseSQLColumnDef()
2549
+ if (col) {
2550
+ actions.push({ type: 'MODIFY', column: col })
2551
+ }
2552
+ }
2553
+
2554
+ return {
2555
+ type: 'AlterTableStatement',
2556
+ name: name,
2557
+ actions: actions
2558
+ }
2559
+ }
2560
+
2561
+ return null
2562
+ }
2563
+
2564
+ parseGraphQLProgram() {
2565
+ const program = {
2566
+ type: 'GraphQLProgram',
2567
+ definitions: []
2568
+ }
2569
+
2570
+ this.skipNewlines()
2571
+
2572
+ while (!this.isAtEnd()) {
2573
+ const def = this.parseGraphQLDefinition()
2574
+ if (def) {
2575
+ program.definitions.push(def)
2576
+ }
2577
+ this.skipNewlines()
2578
+ }
2579
+
2580
+ return program
2581
+ }
2582
+
2583
+ parseGraphQLDefinition() {
2584
+ this.skipNewlines()
2585
+ const token = this.current()
2586
+
2587
+ if (!token || token.type === TokenType.EOF) return null
2588
+
2589
+ const value = token.value ? token.value.toLowerCase() : ''
2590
+
2591
+ if (value === 'type' || value === 'modele') {
2592
+ return this.parseGraphQLType()
2593
+ }
2594
+
2595
+ if (value === 'input' || value === 'entree') {
2596
+ return this.parseGraphQLInput()
2597
+ }
2598
+
2599
+ if (value === 'enum' || value === 'enumeration') {
2600
+ return this.parseGraphQLEnum()
2601
+ }
2602
+
2603
+ if (value === 'interface') {
2604
+ return this.parseGraphQLInterface()
2605
+ }
2606
+
2607
+ if (value === 'query' || value === 'requete') {
2608
+ return this.parseGraphQLQuery()
2609
+ }
2610
+
2611
+ if (value === 'mutation') {
2612
+ return this.parseGraphQLMutation()
2613
+ }
2614
+
2615
+ if (value === 'subscription' || value === 'abonnement') {
2616
+ return this.parseGraphQLSubscription()
2617
+ }
2618
+
2619
+ if (value === 'schema') {
2620
+ return this.parseGraphQLSchema()
2621
+ }
2622
+
2623
+ this.advance()
2624
+ return null
2625
+ }
2626
+
2627
+ parseGraphQLType() {
2628
+ this.advance()
2629
+
2630
+ const nameToken = this.current()
2631
+ let name = null
2632
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2633
+ name = nameToken.value
2634
+ this.advance()
2635
+ }
2636
+
2637
+ let implements_ = []
2638
+ if (this.matchValue('implemente') || this.matchValue('implements')) {
2639
+ while (!this.isAtEnd()) {
2640
+ const implToken = this.current()
2641
+ if (!implToken || implToken.type !== TokenType.IDENTIFIER) break
2642
+
2643
+ const v = implToken.value.toLowerCase()
2644
+ if (v === '{' || this.peek()?.type === TokenType.LBRACE) break
2645
+
2646
+ implements_.push(implToken.value)
2647
+ this.advance()
2648
+
2649
+ if (!this.match(TokenType.AMPERSAND) && !this.match(TokenType.COMMA)) break
2650
+ }
2651
+ }
2652
+
2653
+ this.skipNewlines()
2654
+ const fields = this.parseGraphQLFields()
2655
+
2656
+ return {
2657
+ type: 'TypeDefinition',
2658
+ name: name,
2659
+ implements: implements_,
2660
+ fields: fields
2661
+ }
2662
+ }
2663
+
2664
+ parseGraphQLInput() {
2665
+ this.advance()
2666
+
2667
+ const nameToken = this.current()
2668
+ let name = null
2669
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2670
+ name = nameToken.value
2671
+ this.advance()
2672
+ }
2673
+
2674
+ this.skipNewlines()
2675
+ const fields = this.parseGraphQLFields()
2676
+
2677
+ return {
2678
+ type: 'InputDefinition',
2679
+ name: name,
2680
+ fields: fields
2681
+ }
2682
+ }
2683
+
2684
+ parseGraphQLEnum() {
2685
+ this.advance()
2686
+
2687
+ const nameToken = this.current()
2688
+ let name = null
2689
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2690
+ name = nameToken.value
2691
+ this.advance()
2692
+ }
2693
+
2694
+ const values = []
2695
+
2696
+ if (this.match(TokenType.LBRACE)) {
2697
+ while (!this.isAtEnd() && !this.match(TokenType.RBRACE)) {
2698
+ this.skipNewlines()
2699
+ const valToken = this.current()
2700
+ if (valToken && valToken.type === TokenType.IDENTIFIER) {
2701
+ values.push(valToken.value)
2702
+ this.advance()
2703
+ }
2704
+ this.skipNewlines()
2705
+ }
2706
+ } else {
2707
+ this.skipNewlines()
2708
+ this.match(TokenType.INDENT)
2709
+
2710
+ while (!this.isAtEnd()) {
2711
+ const current = this.current()
2712
+
2713
+ if (current && current.type === TokenType.DEDENT) {
2714
+ this.advance()
2715
+ break
2716
+ }
2717
+
2718
+ if (current && current.type === TokenType.NEWLINE) {
2719
+ this.advance()
2720
+ continue
2721
+ }
2722
+
2723
+ if (current && current.type === TokenType.IDENTIFIER) {
2724
+ values.push(current.value)
2725
+ this.advance()
2726
+ }
2727
+ }
2728
+ }
2729
+
2730
+ return {
2731
+ type: 'EnumDefinition',
2732
+ name: name,
2733
+ values: values
2734
+ }
2735
+ }
2736
+
2737
+ parseGraphQLInterface() {
2738
+ this.advance()
2739
+
2740
+ const nameToken = this.current()
2741
+ let name = null
2742
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2743
+ name = nameToken.value
2744
+ this.advance()
2745
+ }
2746
+
2747
+ this.skipNewlines()
2748
+ const fields = this.parseGraphQLFields()
2749
+
2750
+ return {
2751
+ type: 'InterfaceDefinition',
2752
+ name: name,
2753
+ fields: fields
2754
+ }
2755
+ }
2756
+
2757
+ parseGraphQLFields() {
2758
+ const fields = []
2759
+
2760
+ if (this.match(TokenType.LBRACE)) {
2761
+ while (!this.isAtEnd() && !this.match(TokenType.RBRACE)) {
2762
+ this.skipNewlines()
2763
+ const field = this.parseGraphQLField()
2764
+ if (field) {
2765
+ fields.push(field)
2766
+ }
2767
+ this.skipNewlines()
2768
+ }
2769
+ } else {
2770
+ this.skipNewlines()
2771
+ this.match(TokenType.INDENT)
2772
+
2773
+ while (!this.isAtEnd()) {
2774
+ const current = this.current()
2775
+
2776
+ if (current && current.type === TokenType.DEDENT) {
2777
+ this.advance()
2778
+ break
2779
+ }
2780
+
2781
+ if (current && current.type === TokenType.NEWLINE) {
2782
+ this.advance()
2783
+ continue
2784
+ }
2785
+
2786
+ const field = this.parseGraphQLField()
2787
+ if (field) {
2788
+ fields.push(field)
2789
+ }
2790
+ }
2791
+ }
2792
+
2793
+ return fields
2794
+ }
2795
+
2796
+ parseGraphQLField() {
2797
+ const nameToken = this.current()
2798
+ if (!nameToken || nameToken.type !== TokenType.IDENTIFIER) {
2799
+ return null
2800
+ }
2801
+ const name = nameToken.value
2802
+ this.advance()
2803
+
2804
+ const args = []
2805
+ if (this.match(TokenType.LPAREN)) {
2806
+ while (!this.isAtEnd() && !this.match(TokenType.RPAREN)) {
2807
+ const arg = this.parseGraphQLArg()
2808
+ if (arg) {
2809
+ args.push(arg)
2810
+ }
2811
+ this.match(TokenType.COMMA)
2812
+ }
2813
+ }
2814
+
2815
+ this.match(TokenType.COLON)
2816
+
2817
+ const fieldType = this.parseGraphQLTypeRef()
2818
+
2819
+ const directives = []
2820
+ while (this.match(TokenType.AT)) {
2821
+ const dirToken = this.current()
2822
+ if (dirToken && dirToken.type === TokenType.IDENTIFIER) {
2823
+ directives.push(dirToken.value)
2824
+ this.advance()
2825
+ }
2826
+ }
2827
+
2828
+ return {
2829
+ name: name,
2830
+ args: args,
2831
+ type: fieldType,
2832
+ directives: directives
2833
+ }
2834
+ }
2835
+
2836
+ parseGraphQLArg() {
2837
+ const nameToken = this.current()
2838
+ if (!nameToken || nameToken.type !== TokenType.IDENTIFIER) {
2839
+ return null
2840
+ }
2841
+ const name = nameToken.value
2842
+ this.advance()
2843
+
2844
+ this.match(TokenType.COLON)
2845
+
2846
+ const argType = this.parseGraphQLTypeRef()
2847
+
2848
+ let defaultValue = null
2849
+ if (this.match(TokenType.EQUALS)) {
2850
+ const valToken = this.current()
2851
+ if (valToken) {
2852
+ if (valToken.type === TokenType.STRING) {
2853
+ defaultValue = valToken.value
2854
+ } else if (valToken.type === TokenType.NUMBER || valToken.type === TokenType.INTEGER) {
2855
+ defaultValue = parseFloat(valToken.value)
2856
+ } else if (valToken.type === TokenType.IDENTIFIER) {
2857
+ defaultValue = valToken.value
2858
+ }
2859
+ this.advance()
2860
+ }
2861
+ }
2862
+
2863
+ return {
2864
+ name: name,
2865
+ type: argType,
2866
+ default: defaultValue
2867
+ }
2868
+ }
2869
+
2870
+ parseGraphQLTypeRef() {
2871
+ let isArray = false
2872
+
2873
+ if (this.match(TokenType.LBRACKET)) {
2874
+ isArray = true
2875
+ }
2876
+
2877
+ const typeToken = this.current()
2878
+ let typeName = 'String'
2879
+ if (typeToken && typeToken.type === TokenType.IDENTIFIER) {
2880
+ typeName = this.translateGraphQLType(typeToken.value)
2881
+ this.advance()
2882
+ }
2883
+
2884
+ let isRequired = false
2885
+ if (this.match(TokenType.BANG)) {
2886
+ isRequired = true
2887
+ }
2888
+
2889
+ if (isArray) {
2890
+ this.match(TokenType.RBRACKET)
2891
+ if (this.match(TokenType.BANG)) {
2892
+ isRequired = true
2893
+ }
2894
+ }
2895
+
2896
+ return {
2897
+ name: typeName,
2898
+ isArray: isArray,
2899
+ isRequired: isRequired
2900
+ }
2901
+ }
2902
+
2903
+ translateGraphQLType(value) {
2904
+ const lower = value.toLowerCase()
2905
+
2906
+ const types = {
2907
+ 'chaine': 'String',
2908
+ 'texte': 'String',
2909
+ 'entier': 'Int',
2910
+ 'nombre': 'Int',
2911
+ 'flottant': 'Float',
2912
+ 'decimal': 'Float',
2913
+ 'booleen': 'Boolean',
2914
+ 'identifiant': 'ID',
2915
+ 'id': 'ID'
2916
+ }
2917
+
2918
+ return types[lower] || value
2919
+ }
2920
+
2921
+ parseGraphQLQuery() {
2922
+ this.advance()
2923
+
2924
+ const nameToken = this.current()
2925
+ let name = null
2926
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2927
+ name = nameToken.value
2928
+ this.advance()
2929
+ }
2930
+
2931
+ const args = []
2932
+ if (this.match(TokenType.LPAREN)) {
2933
+ while (!this.isAtEnd() && !this.match(TokenType.RPAREN)) {
2934
+ const arg = this.parseGraphQLArg()
2935
+ if (arg) {
2936
+ args.push(arg)
2937
+ }
2938
+ this.match(TokenType.COMMA)
2939
+ }
2940
+ }
2941
+
2942
+ this.match(TokenType.COLON)
2943
+ const returnType = this.parseGraphQLTypeRef()
2944
+
2945
+ return {
2946
+ type: 'QueryDefinition',
2947
+ name: name,
2948
+ args: args,
2949
+ returnType: returnType
2950
+ }
2951
+ }
2952
+
2953
+ parseGraphQLMutation() {
2954
+ this.advance()
2955
+
2956
+ const nameToken = this.current()
2957
+ let name = null
2958
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2959
+ name = nameToken.value
2960
+ this.advance()
2961
+ }
2962
+
2963
+ const args = []
2964
+ if (this.match(TokenType.LPAREN)) {
2965
+ while (!this.isAtEnd() && !this.match(TokenType.RPAREN)) {
2966
+ const arg = this.parseGraphQLArg()
2967
+ if (arg) {
2968
+ args.push(arg)
2969
+ }
2970
+ this.match(TokenType.COMMA)
2971
+ }
2972
+ }
2973
+
2974
+ this.match(TokenType.COLON)
2975
+ const returnType = this.parseGraphQLTypeRef()
2976
+
2977
+ return {
2978
+ type: 'MutationDefinition',
2979
+ name: name,
2980
+ args: args,
2981
+ returnType: returnType
2982
+ }
2983
+ }
2984
+
2985
+ parseGraphQLSubscription() {
2986
+ this.advance()
2987
+
2988
+ const nameToken = this.current()
2989
+ let name = null
2990
+ if (nameToken && nameToken.type === TokenType.IDENTIFIER) {
2991
+ name = nameToken.value
2992
+ this.advance()
2993
+ }
2994
+
2995
+ const args = []
2996
+ if (this.match(TokenType.LPAREN)) {
2997
+ while (!this.isAtEnd() && !this.match(TokenType.RPAREN)) {
2998
+ const arg = this.parseGraphQLArg()
2999
+ if (arg) {
3000
+ args.push(arg)
3001
+ }
3002
+ this.match(TokenType.COMMA)
3003
+ }
3004
+ }
3005
+
3006
+ this.match(TokenType.COLON)
3007
+ const returnType = this.parseGraphQLTypeRef()
3008
+
3009
+ return {
3010
+ type: 'SubscriptionDefinition',
3011
+ name: name,
3012
+ args: args,
3013
+ returnType: returnType
3014
+ }
3015
+ }
3016
+
3017
+ parseGraphQLSchema() {
3018
+ this.advance()
3019
+
3020
+ const operations = {}
3021
+
3022
+ if (this.match(TokenType.LBRACE)) {
3023
+ while (!this.isAtEnd() && !this.match(TokenType.RBRACE)) {
3024
+ this.skipNewlines()
3025
+ const opToken = this.current()
3026
+
3027
+ if (opToken && opToken.type === TokenType.IDENTIFIER) {
3028
+ const op = opToken.value.toLowerCase()
3029
+ this.advance()
3030
+
3031
+ this.match(TokenType.COLON)
3032
+
3033
+ const typeToken = this.current()
3034
+ if (typeToken && typeToken.type === TokenType.IDENTIFIER) {
3035
+ if (op === 'query' || op === 'requete') {
3036
+ operations.query = typeToken.value
3037
+ } else if (op === 'mutation') {
3038
+ operations.mutation = typeToken.value
3039
+ } else if (op === 'subscription' || op === 'abonnement') {
3040
+ operations.subscription = typeToken.value
3041
+ }
3042
+ this.advance()
3043
+ }
3044
+ }
3045
+
3046
+ this.skipNewlines()
3047
+ }
3048
+ }
3049
+
3050
+ return {
3051
+ type: 'SchemaDefinition',
3052
+ operations: operations
3053
+ }
3054
+ }
3055
+ }
3056
+
3057
+ module.exports = {
3058
+ EtherParser
3059
+ }