@willbooster/tree-sitter-javascript 0.0.0-placeholder.0 → 1.0.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.
package/grammar.js ADDED
@@ -0,0 +1,1129 @@
1
+ /**
2
+ * @file JavaScript grammar for tree-sitter
3
+ * @author Max Brunsfeld <maxbrunsfeld@gmail.com>
4
+ * @author Amaan Qureshi <amaanq12@gmail.com>
5
+ * @license MIT
6
+ */
7
+
8
+ /// <reference types="tree-sitter-cli/dsl" />
9
+ // @ts-check
10
+
11
+ // oxlint-disable-next-line unicorn/prefer-module -- This package is CommonJS, so tree-sitter loads grammar.js as CommonJS.
12
+ module.exports = grammar({
13
+ name: 'javascript',
14
+
15
+ externals: ($) => [
16
+ $._automatic_semicolon,
17
+ $._template_chars,
18
+ $._ternary_qmark,
19
+ $.html_comment,
20
+ '||',
21
+ // We use escape sequence and regex pattern to tell the scanner if we're currently inside a string or template string, in which case
22
+ // it should NOT parse html comments.
23
+ $.escape_sequence,
24
+ $.regex_pattern,
25
+ $.jsx_text,
26
+ ],
27
+
28
+ extras: ($) => [$.comment, $.html_comment, /[\s\p{Zs}\uFEFF\u2028\u2029\u2060\u200B]/u],
29
+
30
+ reserved: {
31
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#reserved_words
32
+ global: () => [
33
+ 'break',
34
+ 'case',
35
+ 'catch',
36
+ 'class',
37
+ 'const',
38
+ 'continue',
39
+ 'debugger',
40
+ 'default',
41
+ 'delete',
42
+ 'do',
43
+ 'else',
44
+ 'export',
45
+ 'extends',
46
+ 'false',
47
+ 'finally',
48
+ 'for',
49
+ 'function',
50
+ 'if',
51
+ 'import',
52
+ 'in',
53
+ 'instanceof',
54
+ 'new',
55
+ 'null',
56
+ 'return',
57
+ 'super',
58
+ 'switch',
59
+ 'this',
60
+ 'throw',
61
+ 'true',
62
+ 'try',
63
+ 'typeof',
64
+ 'var',
65
+ 'void',
66
+ 'while',
67
+ 'with',
68
+ ],
69
+ properties: () => [],
70
+ },
71
+
72
+ supertypes: ($) => [$.statement, $.declaration, $.expression, $.primary_expression, $.pattern],
73
+
74
+ inline: ($) => [
75
+ $._call_signature,
76
+ $._formal_parameter,
77
+ $._expressions,
78
+ $._semicolon,
79
+ $._identifier,
80
+ $._reserved_identifier,
81
+ $._jsx_attribute,
82
+ $._jsx_element_name,
83
+ $._jsx_child,
84
+ $._jsx_element,
85
+ $._jsx_attribute_name,
86
+ $._jsx_attribute_value,
87
+ $._jsx_identifier,
88
+ $._lhs_expression,
89
+ ],
90
+
91
+ precedences: ($) => [
92
+ [
93
+ 'member',
94
+ 'template_call',
95
+ 'call',
96
+ $.update_expression,
97
+ 'unary_void',
98
+ 'binary_exp',
99
+ 'binary_times',
100
+ 'binary_plus',
101
+ 'binary_shift',
102
+ 'binary_compare',
103
+ 'binary_relation',
104
+ 'binary_equality',
105
+ 'bitwise_and',
106
+ 'bitwise_xor',
107
+ 'bitwise_or',
108
+ 'logical_and',
109
+ 'logical_or',
110
+ 'ternary',
111
+ $.sequence_expression,
112
+ $.arrow_function,
113
+ ],
114
+ ['assign', $.primary_expression],
115
+ ['member', 'template_call', 'new', 'call', $.expression],
116
+ ['declaration', 'literal'],
117
+ [$.primary_expression, $.statement_block, 'object'],
118
+ [$.meta_property, $.import],
119
+ [$.import_statement, $.import],
120
+ [$.export_statement, $.primary_expression],
121
+ [$.lexical_declaration, $.primary_expression],
122
+ [$.for_lexical_declaration, $.primary_expression],
123
+ ],
124
+
125
+ conflicts: ($) => [
126
+ [$.primary_expression, $._property_name],
127
+ [$.primary_expression, $.await_expression],
128
+ [$.primary_expression, $.await_expression, $._property_name],
129
+ [$.primary_expression, $.arrow_function],
130
+ [$.primary_expression, $.arrow_function, $._property_name],
131
+ [$.primary_expression, $.method_definition],
132
+ [$.primary_expression, $.rest_pattern],
133
+ [$.primary_expression, $.pattern],
134
+ [$.primary_expression, $._for_header],
135
+ [$.array, $.array_pattern],
136
+ [$.object, $.object_pattern],
137
+ [$.assignment_expression, $.pattern],
138
+ [$.assignment_expression, $.object_assignment_pattern],
139
+ [$.labeled_statement, $._property_name],
140
+ [$.computed_property_name, $.array],
141
+ [$.binary_expression, $._initializer],
142
+ [$.class_static_block, $._property_name],
143
+ ],
144
+
145
+ word: ($) => $.identifier,
146
+
147
+ rules: {
148
+ program: ($) => seq(optional($.hash_bang_line), repeat($.statement)),
149
+
150
+ hash_bang_line: () => /#!.*/,
151
+
152
+ //
153
+ // Export declarations
154
+ //
155
+
156
+ export_statement: ($) =>
157
+ choice(
158
+ seq(
159
+ 'export',
160
+ choice(
161
+ seq('*', $._from_clause),
162
+ seq($.namespace_export, $._from_clause),
163
+ seq($.export_clause, $._from_clause),
164
+ $.export_clause
165
+ ),
166
+ $._semicolon
167
+ ),
168
+ seq(
169
+ repeat(field('decorator', $.decorator)),
170
+ 'export',
171
+ choice(
172
+ field('declaration', $.declaration),
173
+ seq('default', choice(field('declaration', $.declaration), seq(field('value', $.expression), $._semicolon)))
174
+ )
175
+ )
176
+ ),
177
+
178
+ namespace_export: ($) => seq('*', 'as', $._module_export_name),
179
+
180
+ export_clause: ($) => seq('{', commaSep($.export_specifier), optional(','), '}'),
181
+
182
+ export_specifier: ($) =>
183
+ seq(field('name', $._module_export_name), optional(seq('as', field('alias', $._module_export_name)))),
184
+
185
+ _module_export_name: ($) => choice($.identifier, $.string, 'default'),
186
+
187
+ declaration: ($) =>
188
+ choice(
189
+ $.function_declaration,
190
+ $.generator_function_declaration,
191
+ $.class_declaration,
192
+ $.lexical_declaration,
193
+ $.variable_declaration,
194
+ $.using_declaration
195
+ ),
196
+
197
+ //
198
+ // Import declarations
199
+ //
200
+
201
+ import: () => token('import'),
202
+
203
+ import_statement: ($) =>
204
+ seq(
205
+ 'import',
206
+ choice(seq($.import_clause, $._from_clause), field('source', $.string)),
207
+ optional($.import_attribute),
208
+ $._semicolon
209
+ ),
210
+
211
+ import_clause: ($) =>
212
+ choice(
213
+ $.namespace_import,
214
+ $.named_imports,
215
+ seq($.identifier, optional(seq(',', choice($.namespace_import, $.named_imports))))
216
+ ),
217
+
218
+ _from_clause: ($) => seq('from', field('source', $.string)),
219
+
220
+ namespace_import: ($) => seq('*', 'as', $.identifier),
221
+
222
+ named_imports: ($) => seq('{', commaSep($.import_specifier), optional(','), '}'),
223
+
224
+ import_specifier: ($) =>
225
+ choice(
226
+ field('name', $.identifier),
227
+ seq(field('name', $._module_export_name), 'as', field('alias', $.identifier))
228
+ ),
229
+
230
+ import_attribute: ($) => seq('with', $.object),
231
+
232
+ //
233
+ // Statements
234
+ //
235
+
236
+ statement: ($) =>
237
+ choice(
238
+ $.export_statement,
239
+ $.import_statement,
240
+ $.debugger_statement,
241
+ $.expression_statement,
242
+ $.declaration,
243
+ $.statement_block,
244
+
245
+ $.if_statement,
246
+ $.switch_statement,
247
+ $.for_statement,
248
+ $.for_in_statement,
249
+ $.while_statement,
250
+ $.do_statement,
251
+ $.try_statement,
252
+ $.with_statement,
253
+
254
+ $.break_statement,
255
+ $.continue_statement,
256
+ $.return_statement,
257
+ $.throw_statement,
258
+ $.empty_statement,
259
+ $.labeled_statement
260
+ ),
261
+
262
+ expression_statement: ($) => seq($._expressions, $._semicolon),
263
+
264
+ variable_declaration: ($) => seq('var', commaSep1($.variable_declarator), $._semicolon),
265
+
266
+ lexical_declaration: ($) =>
267
+ seq(field('kind', choice('let', 'const')), commaSep1($.variable_declarator), $._semicolon),
268
+
269
+ using_declaration: ($) =>
270
+ seq(field('kind', choice('using', seq('await', 'using'))), commaSep1($.variable_declarator), $._semicolon),
271
+
272
+ variable_declarator: ($) =>
273
+ seq(
274
+ field('name', choice($.identifier, alias('of', $.identifier), $._destructuring_pattern)),
275
+ optional($._initializer)
276
+ ),
277
+
278
+ statement_block: ($) => prec.right(seq('{', repeat($.statement), '}', optional($._automatic_semicolon))),
279
+
280
+ else_clause: ($) => seq('else', $.statement),
281
+
282
+ if_statement: ($) =>
283
+ prec.right(
284
+ seq(
285
+ 'if',
286
+ field('condition', $.parenthesized_expression),
287
+ field('consequence', $.statement),
288
+ optional(field('alternative', $.else_clause))
289
+ )
290
+ ),
291
+
292
+ switch_statement: ($) => seq('switch', field('value', $.parenthesized_expression), field('body', $.switch_body)),
293
+
294
+ for_statement: ($) =>
295
+ seq(
296
+ 'for',
297
+ '(',
298
+ choice(
299
+ field(
300
+ 'initializer',
301
+ choice(
302
+ alias($.for_lexical_declaration, $.lexical_declaration),
303
+ alias($.for_variable_declaration, $.variable_declaration)
304
+ )
305
+ ),
306
+ seq(field('initializer', $._expressions), ';'),
307
+ field('initializer', $.empty_statement)
308
+ ),
309
+ field('condition', choice(seq($._expressions, ';'), $.empty_statement)),
310
+ field('increment', optional($._expressions)),
311
+ ')',
312
+ field('body', $.statement)
313
+ ),
314
+
315
+ // ECMAScript inserts no semicolon inside a for header, so these declarations end only with `;`. Accepting an
316
+ // automatic semicolon there made `for (let x\n of y)` ambiguous until `of`, and an incremental reparse could
317
+ // reuse a declaration built when that ambiguity was resolved differently. The rules are visible and only used
318
+ // through aliases: a hidden rule would make `for_statement` inherit their `kind` field.
319
+ for_lexical_declaration: ($) => seq(field('kind', choice('let', 'const')), commaSep1($.variable_declarator), ';'),
320
+
321
+ for_variable_declaration: ($) => seq('var', commaSep1($.variable_declarator), ';'),
322
+
323
+ for_in_statement: ($) => seq('for', optional('await'), $._for_header, field('body', $.statement)),
324
+
325
+ _for_header: ($) =>
326
+ seq(
327
+ '(',
328
+ choice(
329
+ field('left', choice($._lhs_expression, $.parenthesized_expression)),
330
+ seq(
331
+ field('kind', 'var'),
332
+ field('left', choice($.identifier, alias('of', $.identifier), $._destructuring_pattern)),
333
+ optional($._initializer)
334
+ ),
335
+ seq(
336
+ field('kind', choice('let', 'const')),
337
+ field('left', choice($.identifier, alias('of', $.identifier), $._destructuring_pattern))
338
+ ),
339
+ seq(
340
+ field('kind', choice('using', seq('await', 'using'))),
341
+ field('left', choice($.identifier, alias('of', $.identifier), $._destructuring_pattern))
342
+ )
343
+ ),
344
+ field('operator', choice('in', 'of')),
345
+ field('right', $._expressions),
346
+ ')'
347
+ ),
348
+
349
+ while_statement: ($) => seq('while', field('condition', $.parenthesized_expression), field('body', $.statement)),
350
+
351
+ do_statement: ($) =>
352
+ prec.right(
353
+ seq(
354
+ 'do',
355
+ field('body', $.statement),
356
+ 'while',
357
+ field('condition', $.parenthesized_expression),
358
+ optional($._semicolon)
359
+ )
360
+ ),
361
+
362
+ try_statement: ($) =>
363
+ seq(
364
+ 'try',
365
+ field('body', $.statement_block),
366
+ optional(field('handler', $.catch_clause)),
367
+ optional(field('finalizer', $.finally_clause))
368
+ ),
369
+
370
+ with_statement: ($) => seq('with', field('object', $.parenthesized_expression), field('body', $.statement)),
371
+
372
+ break_statement: ($) =>
373
+ seq('break', field('label', optional(alias($.identifier, $.statement_identifier))), $._semicolon),
374
+
375
+ continue_statement: ($) =>
376
+ seq('continue', field('label', optional(alias($.identifier, $.statement_identifier))), $._semicolon),
377
+
378
+ debugger_statement: ($) => seq('debugger', $._semicolon),
379
+
380
+ return_statement: ($) => seq('return', optional($._expressions), $._semicolon),
381
+
382
+ throw_statement: ($) => seq('throw', $._expressions, $._semicolon),
383
+
384
+ empty_statement: () => ';',
385
+
386
+ labeled_statement: ($) =>
387
+ prec.dynamic(
388
+ -1,
389
+ seq(
390
+ field('label', alias(choice($.identifier, $._reserved_identifier), $.statement_identifier)),
391
+ ':',
392
+ field('body', $.statement)
393
+ )
394
+ ),
395
+
396
+ //
397
+ // Statement components
398
+ //
399
+
400
+ switch_body: ($) => seq('{', repeat(choice($.switch_case, $.switch_default)), '}'),
401
+
402
+ switch_case: ($) => seq('case', field('value', $._expressions), ':', field('body', repeat($.statement))),
403
+
404
+ switch_default: ($) => seq('default', ':', field('body', repeat($.statement))),
405
+
406
+ catch_clause: ($) =>
407
+ seq(
408
+ 'catch',
409
+ optional(seq('(', field('parameter', choice($.identifier, $._destructuring_pattern)), ')')),
410
+ field('body', $.statement_block)
411
+ ),
412
+
413
+ finally_clause: ($) => seq('finally', field('body', $.statement_block)),
414
+
415
+ parenthesized_expression: ($) => seq('(', $._expressions, ')'),
416
+
417
+ //
418
+ // Expressions
419
+ //
420
+ _expressions: ($) => choice($.expression, $.sequence_expression),
421
+
422
+ expression: ($) =>
423
+ choice(
424
+ $.primary_expression,
425
+ $._jsx_element,
426
+ $.assignment_expression,
427
+ $.augmented_assignment_expression,
428
+ $.await_expression,
429
+ $.unary_expression,
430
+ $.binary_expression,
431
+ $.ternary_expression,
432
+ $.update_expression,
433
+ $.new_expression,
434
+ $.yield_expression
435
+ ),
436
+
437
+ primary_expression: ($) =>
438
+ choice(
439
+ $.subscript_expression,
440
+ $.member_expression,
441
+ $.parenthesized_expression,
442
+ $._identifier,
443
+ alias($._reserved_identifier, $.identifier),
444
+ $.this,
445
+ $.super,
446
+ $.number,
447
+ $.string,
448
+ $.template_string,
449
+ $.regex,
450
+ $.true,
451
+ $.false,
452
+ $.null,
453
+ $.object,
454
+ $.array,
455
+ $.function_expression,
456
+ $.arrow_function,
457
+ $.generator_function,
458
+ $.class,
459
+ $.meta_property,
460
+ $.call_expression
461
+ ),
462
+
463
+ yield_expression: ($) => prec.right(seq('yield', choice(seq('*', $.expression), optional($.expression)))),
464
+
465
+ object: ($) =>
466
+ prec(
467
+ 'object',
468
+ seq(
469
+ '{',
470
+ commaSep(
471
+ optional(
472
+ choice(
473
+ $.pair,
474
+ $.spread_element,
475
+ $.method_definition,
476
+ alias(choice($.identifier, $._reserved_identifier), $.shorthand_property_identifier)
477
+ )
478
+ )
479
+ ),
480
+ '}'
481
+ )
482
+ ),
483
+
484
+ object_pattern: ($) =>
485
+ prec(
486
+ 'object',
487
+ seq(
488
+ '{',
489
+ commaSep(
490
+ optional(
491
+ choice(
492
+ $.pair_pattern,
493
+ $.rest_pattern,
494
+ $.object_assignment_pattern,
495
+ alias(choice($.identifier, $._reserved_identifier), $.shorthand_property_identifier_pattern)
496
+ )
497
+ )
498
+ ),
499
+ '}'
500
+ )
501
+ ),
502
+
503
+ assignment_pattern: ($) => seq(field('left', $.pattern), '=', field('right', $.expression)),
504
+
505
+ object_assignment_pattern: ($) =>
506
+ seq(
507
+ field(
508
+ 'left',
509
+ choice(
510
+ alias(choice($._reserved_identifier, $.identifier), $.shorthand_property_identifier_pattern),
511
+ $._destructuring_pattern
512
+ )
513
+ ),
514
+ '=',
515
+ field('right', $.expression)
516
+ ),
517
+
518
+ array: ($) => seq('[', commaSep(optional(choice($.expression, $.spread_element))), ']'),
519
+
520
+ array_pattern: ($) => seq('[', commaSep(optional(choice($.pattern, $.assignment_pattern))), ']'),
521
+
522
+ _jsx_element: ($) => choice($.jsx_element, $.jsx_self_closing_element),
523
+
524
+ jsx_element: ($) =>
525
+ seq(field('open_tag', $.jsx_opening_element), repeat($._jsx_child), field('close_tag', $.jsx_closing_element)),
526
+
527
+ // An entity can be named, numeric (decimal), or numeric (hexadecimal). The
528
+ // longest entity name is 29 characters long, and the HTML spec says that
529
+ // no more will ever be added.
530
+ html_character_reference: () => /&(#([xX][0-9a-fA-F]{1,6}|[0-9]{1,5})|[A-Za-z]{1,30});/,
531
+
532
+ jsx_expression: ($) => seq('{', optional(choice($.expression, $.sequence_expression, $.spread_element)), '}'),
533
+
534
+ _jsx_child: ($) => choice($.jsx_text, $.html_character_reference, $._jsx_element, $.jsx_expression),
535
+
536
+ jsx_opening_element: ($) =>
537
+ prec.dynamic(
538
+ -1,
539
+ seq('<', optional(seq(field('name', $._jsx_element_name), repeat(field('attribute', $._jsx_attribute)))), '>')
540
+ ),
541
+
542
+ jsx_identifier: () => /[a-zA-Z_$][a-zA-Z\d_$]*-[a-zA-Z\d_$-]*/,
543
+
544
+ _jsx_identifier: ($) => choice(alias($.jsx_identifier, $.identifier), $.identifier),
545
+
546
+ nested_identifier: ($) =>
547
+ prec(
548
+ 'member',
549
+ seq(
550
+ field('object', choice($.identifier, alias($.nested_identifier, $.member_expression))),
551
+ '.',
552
+ field('property', alias($.identifier, $.property_identifier))
553
+ )
554
+ ),
555
+
556
+ jsx_namespace_name: ($) => seq($._jsx_identifier, ':', $._jsx_identifier),
557
+
558
+ _jsx_element_name: ($) =>
559
+ choice($._jsx_identifier, alias($.nested_identifier, $.member_expression), $.jsx_namespace_name),
560
+
561
+ jsx_closing_element: ($) => seq('</', optional(field('name', $._jsx_element_name)), '>'),
562
+
563
+ jsx_self_closing_element: ($) =>
564
+ seq('<', field('name', $._jsx_element_name), repeat(field('attribute', $._jsx_attribute)), '/>'),
565
+
566
+ _jsx_attribute: ($) => choice($.jsx_attribute, $.jsx_expression),
567
+
568
+ _jsx_attribute_name: ($) => choice(alias($._jsx_identifier, $.property_identifier), $.jsx_namespace_name),
569
+
570
+ jsx_attribute: ($) => seq($._jsx_attribute_name, optional(seq('=', $._jsx_attribute_value))),
571
+
572
+ _jsx_string: ($) =>
573
+ choice(
574
+ seq(
575
+ '"',
576
+ repeat(choice(alias($.unescaped_double_jsx_string_fragment, $.string_fragment), $.html_character_reference)),
577
+ '"'
578
+ ),
579
+ seq(
580
+ "'",
581
+ repeat(choice(alias($.unescaped_single_jsx_string_fragment, $.string_fragment), $.html_character_reference)),
582
+ "'"
583
+ )
584
+ ),
585
+
586
+ // Workaround to https://github.com/tree-sitter/tree-sitter/issues/1156
587
+ // We give names to the token() constructs containing a regexp
588
+ // so as to obtain a node in the CST.
589
+ //
590
+ unescaped_double_jsx_string_fragment: () => token.immediate(prec(1, /([^"&]|&[^#A-Za-z])+/)),
591
+
592
+ // same here
593
+ unescaped_single_jsx_string_fragment: () => token.immediate(prec(1, /([^'&]|&[^#A-Za-z])+/)),
594
+
595
+ _jsx_attribute_value: ($) => choice(alias($._jsx_string, $.string), $.jsx_expression, $._jsx_element),
596
+
597
+ class: ($) =>
598
+ prec(
599
+ 'literal',
600
+ seq(
601
+ repeat(field('decorator', $.decorator)),
602
+ 'class',
603
+ field('name', optional($.identifier)),
604
+ optional($.class_heritage),
605
+ field('body', $.class_body)
606
+ )
607
+ ),
608
+
609
+ class_declaration: ($) =>
610
+ prec(
611
+ 'declaration',
612
+ seq(
613
+ repeat(field('decorator', $.decorator)),
614
+ 'class',
615
+ field('name', $.identifier),
616
+ optional($.class_heritage),
617
+ field('body', $.class_body),
618
+ optional($._automatic_semicolon)
619
+ )
620
+ ),
621
+
622
+ class_heritage: ($) => seq('extends', $.expression),
623
+
624
+ function_expression: ($) =>
625
+ prec(
626
+ 'literal',
627
+ seq(
628
+ optional('async'),
629
+ 'function',
630
+ field('name', optional($.identifier)),
631
+ $._call_signature,
632
+ field('body', $.statement_block)
633
+ )
634
+ ),
635
+
636
+ function_declaration: ($) =>
637
+ prec.right(
638
+ 'declaration',
639
+ seq(
640
+ optional('async'),
641
+ 'function',
642
+ field('name', $.identifier),
643
+ $._call_signature,
644
+ field('body', $.statement_block),
645
+ optional($._automatic_semicolon)
646
+ )
647
+ ),
648
+
649
+ generator_function: ($) =>
650
+ prec(
651
+ 'literal',
652
+ seq(
653
+ optional('async'),
654
+ 'function',
655
+ '*',
656
+ field('name', optional($.identifier)),
657
+ $._call_signature,
658
+ field('body', $.statement_block)
659
+ )
660
+ ),
661
+
662
+ generator_function_declaration: ($) =>
663
+ prec.right(
664
+ 'declaration',
665
+ seq(
666
+ optional('async'),
667
+ 'function',
668
+ '*',
669
+ field('name', $.identifier),
670
+ $._call_signature,
671
+ field('body', $.statement_block),
672
+ optional($._automatic_semicolon)
673
+ )
674
+ ),
675
+
676
+ arrow_function: ($) =>
677
+ seq(
678
+ optional('async'),
679
+ choice(
680
+ field('parameter', choice(alias($._reserved_identifier, $.identifier), $.identifier)),
681
+ $._call_signature
682
+ ),
683
+ '=>',
684
+ field('body', choice($.expression, $.statement_block))
685
+ ),
686
+
687
+ // Override
688
+ _call_signature: ($) => field('parameters', $.formal_parameters),
689
+ _formal_parameter: ($) => choice($.pattern, $.assignment_pattern),
690
+
691
+ optional_chain: () => '?.',
692
+
693
+ call_expression: ($) =>
694
+ choice(
695
+ prec('call', seq(field('function', choice($.expression, $.import)), field('arguments', $.arguments))),
696
+ prec(
697
+ 'template_call',
698
+ seq(field('function', choice($.primary_expression, $.new_expression)), field('arguments', $.template_string))
699
+ ),
700
+ prec(
701
+ 'member',
702
+ seq(
703
+ field('function', $.primary_expression),
704
+ field('optional_chain', $.optional_chain),
705
+ field('arguments', $.arguments)
706
+ )
707
+ )
708
+ ),
709
+
710
+ new_expression: ($) =>
711
+ prec.right(
712
+ 'new',
713
+ seq(
714
+ 'new',
715
+ field('constructor', choice($.primary_expression, $.new_expression)),
716
+ field('arguments', optional(prec.dynamic(1, $.arguments)))
717
+ )
718
+ ),
719
+
720
+ await_expression: ($) => prec('unary_void', seq('await', $.expression)),
721
+
722
+ member_expression: ($) =>
723
+ prec(
724
+ 'member',
725
+ seq(
726
+ field('object', choice($.expression, $.primary_expression, $.import)),
727
+ choice('.', field('optional_chain', $.optional_chain)),
728
+ field(
729
+ 'property',
730
+ choice($.private_property_identifier, reserved('properties', alias($.identifier, $.property_identifier)))
731
+ )
732
+ )
733
+ ),
734
+
735
+ subscript_expression: ($) =>
736
+ prec.right(
737
+ 'member',
738
+ seq(
739
+ field('object', choice($.expression, $.primary_expression)),
740
+ optional(field('optional_chain', $.optional_chain)),
741
+ '[',
742
+ field('index', $._expressions),
743
+ ']'
744
+ )
745
+ ),
746
+
747
+ _lhs_expression: ($) =>
748
+ choice(
749
+ $.member_expression,
750
+ $.subscript_expression,
751
+ $._identifier,
752
+ alias($._reserved_identifier, $.identifier),
753
+ $._destructuring_pattern
754
+ ),
755
+
756
+ assignment_expression: ($) =>
757
+ prec.right(
758
+ 'assign',
759
+ seq(field('left', choice($.parenthesized_expression, $._lhs_expression)), '=', field('right', $.expression))
760
+ ),
761
+
762
+ _augmented_assignment_lhs: ($) =>
763
+ choice(
764
+ $.member_expression,
765
+ $.subscript_expression,
766
+ alias($._reserved_identifier, $.identifier),
767
+ $.identifier,
768
+ $.parenthesized_expression
769
+ ),
770
+
771
+ augmented_assignment_expression: ($) =>
772
+ prec.right(
773
+ 'assign',
774
+ seq(
775
+ field('left', $._augmented_assignment_lhs),
776
+ field(
777
+ 'operator',
778
+ choice('+=', '-=', '*=', '/=', '%=', '^=', '&=', '|=', '>>=', '>>>=', '<<=', '**=', '&&=', '||=', '??=')
779
+ ),
780
+ field('right', $.expression)
781
+ )
782
+ ),
783
+
784
+ _initializer: ($) => seq('=', field('value', $.expression)),
785
+
786
+ _destructuring_pattern: ($) => choice($.object_pattern, $.array_pattern),
787
+
788
+ spread_element: ($) => seq('...', $.expression),
789
+
790
+ ternary_expression: ($) =>
791
+ prec.right(
792
+ 'ternary',
793
+ seq(
794
+ field('condition', $.expression),
795
+ alias($._ternary_qmark, '?'),
796
+ field('consequence', $.expression),
797
+ ':',
798
+ field('alternative', $.expression)
799
+ )
800
+ ),
801
+
802
+ binary_expression: ($) =>
803
+ choice(
804
+ ...[
805
+ ['&&', 'logical_and'],
806
+ ['||', 'logical_or'],
807
+ ['>>', 'binary_shift'],
808
+ ['>>>', 'binary_shift'],
809
+ ['<<', 'binary_shift'],
810
+ ['&', 'bitwise_and'],
811
+ ['^', 'bitwise_xor'],
812
+ ['|', 'bitwise_or'],
813
+ ['+', 'binary_plus'],
814
+ ['-', 'binary_plus'],
815
+ ['*', 'binary_times'],
816
+ ['/', 'binary_times'],
817
+ ['%', 'binary_times'],
818
+ ['**', 'binary_exp', 'right'],
819
+ ['<', 'binary_relation'],
820
+ ['<=', 'binary_relation'],
821
+ ['==', 'binary_equality'],
822
+ ['===', 'binary_equality'],
823
+ ['!=', 'binary_equality'],
824
+ ['!==', 'binary_equality'],
825
+ ['>=', 'binary_relation'],
826
+ ['>', 'binary_relation'],
827
+ ['??', 'ternary'],
828
+ ['instanceof', 'binary_relation'],
829
+ ['in', 'binary_relation'],
830
+ ].map(([operator, precedence, associativity]) =>
831
+ // oxlint-disable-next-line typescript/unbound-method -- prec.left and prec.right do not use `this`.
832
+ (associativity === 'right' ? prec.right : prec.left)(
833
+ precedence,
834
+ seq(
835
+ field('left', operator === 'in' ? choice($.expression, $.private_property_identifier) : $.expression),
836
+ field('operator', operator),
837
+ field('right', $.expression)
838
+ )
839
+ )
840
+ )
841
+ ),
842
+
843
+ unary_expression: ($) =>
844
+ prec.left(
845
+ 'unary_void',
846
+ seq(field('operator', choice('!', '~', '-', '+', 'typeof', 'void', 'delete')), field('argument', $.expression))
847
+ ),
848
+
849
+ update_expression: ($) =>
850
+ prec.left(
851
+ choice(
852
+ seq(field('argument', $.expression), field('operator', choice('++', '--'))),
853
+ seq(field('operator', choice('++', '--')), field('argument', $.expression))
854
+ )
855
+ ),
856
+
857
+ sequence_expression: ($) => prec.right(commaSep1($.expression)),
858
+
859
+ //
860
+ // Primitives
861
+ //
862
+
863
+ string: ($) =>
864
+ choice(
865
+ seq('"', repeat(choice(alias($.unescaped_double_string_fragment, $.string_fragment), $.escape_sequence)), '"'),
866
+ seq("'", repeat(choice(alias($.unescaped_single_string_fragment, $.string_fragment), $.escape_sequence)), "'")
867
+ ),
868
+
869
+ // Workaround to https://github.com/tree-sitter/tree-sitter/issues/1156
870
+ // We give names to the token() constructs containing a regexp
871
+ // so as to obtain a node in the CST.
872
+ //
873
+ unescaped_double_string_fragment: () => token.immediate(prec(1, /[^"\\\r\n]+/)),
874
+
875
+ // same here
876
+ unescaped_single_string_fragment: () => token.immediate(prec(1, /[^'\\\r\n]+/)),
877
+
878
+ escape_sequence: () =>
879
+ token.immediate(
880
+ seq(
881
+ '\\',
882
+ choice(
883
+ /[^xu0-7]/,
884
+ /[0-7]{1,3}/,
885
+ /x[0-9a-fA-F]{2}/,
886
+ /u[0-9a-fA-F]{4}/,
887
+ /u\{[0-9a-fA-F]+\}/,
888
+ /[\r?][\n\u2028\u2029]/
889
+ )
890
+ )
891
+ ),
892
+
893
+ // http://stackoverflow.com/questions/13014947/regex-to-match-a-c-style-multiline-comment/36328890#36328890
894
+ comment: () => token(choice(seq('//', /[^\r\n\u2028\u2029]*/), seq('/*', /[^*]*\*+([^/*][^*]*\*+)*/, '/'))),
895
+
896
+ template_string: ($) =>
897
+ seq(
898
+ '`',
899
+ repeat(choice(alias($._template_chars, $.string_fragment), $.escape_sequence, $.template_substitution)),
900
+ '`'
901
+ ),
902
+
903
+ template_substitution: ($) => seq('${', $._expressions, '}'),
904
+
905
+ regex: ($) =>
906
+ seq(
907
+ '/',
908
+ field('pattern', $.regex_pattern),
909
+ token.immediate(prec(1, '/')),
910
+ optional(field('flags', $.regex_flags))
911
+ ),
912
+
913
+ regex_pattern: () =>
914
+ token.immediate(
915
+ prec(
916
+ -1,
917
+ repeat1(
918
+ choice(
919
+ seq(
920
+ '[',
921
+ repeat(
922
+ choice(
923
+ seq('\\', /./), // escaped character
924
+ /[^\]\n\\]/ // any character besides ']' or '\n'
925
+ )
926
+ ),
927
+ ']'
928
+ ), // square-bracket-delimited character class
929
+ seq('\\', /./), // escaped character
930
+ // oxlint-disable-next-line no-useless-escape -- tree-sitter's regex parser rejects an unescaped `[` in a character class.
931
+ /[^/\\\[\n]/ // any character besides '[', '\', '/', '\n'
932
+ )
933
+ )
934
+ )
935
+ ),
936
+
937
+ regex_flags: () => token.immediate(/[a-z]+/),
938
+
939
+ number: () => {
940
+ const hexLiteral = seq(choice('0x', '0X'), /[\da-fA-F](_?[\da-fA-F])*/);
941
+
942
+ const decimalDigits = /\d(_?\d)*/;
943
+ const signedInteger = seq(optional(choice('-', '+')), decimalDigits);
944
+ const exponentPart = seq(choice('e', 'E'), signedInteger);
945
+
946
+ const binaryLiteral = seq(choice('0b', '0B'), /[0-1](_?[0-1])*/);
947
+
948
+ const octalLiteral = seq(choice('0o', '0O'), /[0-7](_?[0-7])*/);
949
+
950
+ const bigintLiteral = seq(choice(hexLiteral, binaryLiteral, octalLiteral, decimalDigits), 'n');
951
+
952
+ const decimalIntegerLiteral = choice(
953
+ '0',
954
+ seq(optional('0'), /[1-9]/, optional(seq(optional('_'), decimalDigits)))
955
+ );
956
+
957
+ const decimalLiteral = choice(
958
+ seq(decimalIntegerLiteral, '.', optional(decimalDigits), optional(exponentPart)),
959
+ seq('.', decimalDigits, optional(exponentPart)),
960
+ seq(decimalIntegerLiteral, exponentPart),
961
+ decimalDigits
962
+ );
963
+
964
+ return token(choice(hexLiteral, decimalLiteral, binaryLiteral, octalLiteral, bigintLiteral));
965
+ },
966
+
967
+ // 'undefined' is syntactically a regular identifier in JavaScript.
968
+ // However, its main use is as the read-only global variable whose
969
+ // value is [undefined], for which there's no literal representation
970
+ // unlike 'null'. We gave it its own rule so it's easy to
971
+ // highlight in text editors and other applications.
972
+ _identifier: ($) => choice($.undefined, $.identifier),
973
+
974
+ identifier: () => {
975
+ const alpha =
976
+ // oxlint-disable-next-line no-control-regex, no-useless-escape -- Identifiers exclude control characters, and tree-sitter's regex parser rejects an unescaped `[` in a character class.
977
+ /[^\u0000-\u001F\s\p{Zs}0-9:;`"'@#.,|^&<=>+\-*/\\%?!~()\[\]{}\uFEFF\u2060\u200B\u2028\u2029]|\\u[0-9a-fA-F]{4}|\\u\{[0-9a-fA-F]+\}/u;
978
+
979
+ const alphanumeric =
980
+ // oxlint-disable-next-line no-control-regex, no-useless-escape -- Identifiers exclude control characters, and tree-sitter's regex parser rejects an unescaped `[` in a character class.
981
+ /[^\u0000-\u001F\s\p{Zs}:;`"'@#.,|^&<=>+\-*/\\%?!~()\[\]{}\uFEFF\u2060\u200B\u2028\u2029]|\\u[0-9a-fA-F]{4}|\\u\{[0-9a-fA-F]+\}/u;
982
+ return token(seq(alpha, repeat(alphanumeric)));
983
+ },
984
+
985
+ private_property_identifier: () => {
986
+ const alpha =
987
+ // oxlint-disable-next-line no-control-regex, no-useless-escape -- Identifiers exclude control characters, and tree-sitter's regex parser rejects an unescaped `[` in a character class.
988
+ /[^\u0000-\u001F\s\p{Zs}0-9:;`"'@#.,|^&<=>+\-*/\\%?!~()\[\]{}\uFEFF\u2060\u200B\u2028\u2029]|\\u[0-9a-fA-F]{4}|\\u\{[0-9a-fA-F]+\}/u;
989
+
990
+ const alphanumeric =
991
+ // oxlint-disable-next-line no-control-regex, no-useless-escape -- Identifiers exclude control characters, and tree-sitter's regex parser rejects an unescaped `[` in a character class.
992
+ /[^\u0000-\u001F\s\p{Zs}:;`"'@#.,|^&<=>+\-*/\\%?!~()\[\]{}\uFEFF\u2060\u200B\u2028\u2029]|\\u[0-9a-fA-F]{4}|\\u\{[0-9a-fA-F]+\}/u;
993
+ return token(seq('#', alpha, repeat(alphanumeric)));
994
+ },
995
+
996
+ meta_property: () => choice(seq('new', '.', 'target'), seq('import', '.', 'meta')),
997
+
998
+ this: () => 'this',
999
+ super: () => 'super',
1000
+ true: () => 'true',
1001
+ false: () => 'false',
1002
+ null: () => 'null',
1003
+ undefined: () => 'undefined',
1004
+
1005
+ //
1006
+ // Expression components
1007
+ //
1008
+
1009
+ arguments: ($) => seq('(', commaSep(optional(choice($.expression, $.spread_element))), ')'),
1010
+
1011
+ decorator: ($) =>
1012
+ seq(
1013
+ '@',
1014
+ choice(
1015
+ $.identifier,
1016
+ alias($.decorator_member_expression, $.member_expression),
1017
+ alias($.decorator_call_expression, $.call_expression)
1018
+ )
1019
+ ),
1020
+
1021
+ decorator_member_expression: ($) =>
1022
+ prec(
1023
+ 'member',
1024
+ seq(
1025
+ field('object', choice($.identifier, alias($.decorator_member_expression, $.member_expression))),
1026
+ '.',
1027
+ field('property', alias($.identifier, $.property_identifier))
1028
+ )
1029
+ ),
1030
+
1031
+ decorator_call_expression: ($) =>
1032
+ prec(
1033
+ 'call',
1034
+ seq(
1035
+ field('function', choice($.identifier, alias($.decorator_member_expression, $.member_expression))),
1036
+ field('arguments', $.arguments)
1037
+ )
1038
+ ),
1039
+
1040
+ class_body: ($) =>
1041
+ seq(
1042
+ '{',
1043
+ repeat(
1044
+ choice(
1045
+ seq(field('member', $.method_definition), optional(';')),
1046
+ seq(field('member', $.field_definition), $._semicolon),
1047
+ field('member', $.class_static_block),
1048
+ ';'
1049
+ )
1050
+ ),
1051
+ '}'
1052
+ ),
1053
+
1054
+ field_definition: ($) =>
1055
+ seq(
1056
+ repeat(field('decorator', $.decorator)),
1057
+ optional('static'),
1058
+ field('property', $._property_name),
1059
+ optional($._initializer)
1060
+ ),
1061
+
1062
+ formal_parameters: ($) => seq('(', optional(seq(commaSep1($._formal_parameter), optional(','))), ')'),
1063
+
1064
+ class_static_block: ($) => seq('static', optional($._automatic_semicolon), field('body', $.statement_block)),
1065
+
1066
+ // This negative dynamic precedence ensures that during error recovery,
1067
+ // unfinished constructs are generally treated as literal expressions,
1068
+ // not patterns.
1069
+ pattern: ($) => prec.dynamic(-1, choice($._lhs_expression, $.rest_pattern)),
1070
+
1071
+ rest_pattern: ($) => prec.right(seq('...', $._lhs_expression)),
1072
+
1073
+ method_definition: ($) =>
1074
+ seq(
1075
+ repeat(field('decorator', $.decorator)),
1076
+ optional(choice('static', alias(token(seq('static', /\s+/, 'get', /\s*\n/)), 'static get'))),
1077
+ optional('async'),
1078
+ optional(choice('get', 'set', '*')),
1079
+ field('name', $._property_name),
1080
+ field('parameters', $.formal_parameters),
1081
+ field('body', $.statement_block)
1082
+ ),
1083
+
1084
+ pair: ($) => seq(field('key', $._property_name), ':', field('value', $.expression)),
1085
+
1086
+ pair_pattern: ($) =>
1087
+ seq(field('key', $._property_name), ':', field('value', choice($.pattern, $.assignment_pattern))),
1088
+
1089
+ _property_name: ($) =>
1090
+ reserved(
1091
+ 'properties',
1092
+ choice(
1093
+ alias(choice($.identifier, $._reserved_identifier), $.property_identifier),
1094
+ $.private_property_identifier,
1095
+ $.string,
1096
+ $.number,
1097
+ $.computed_property_name
1098
+ )
1099
+ ),
1100
+
1101
+ computed_property_name: ($) => seq('[', $.expression, ']'),
1102
+
1103
+ _reserved_identifier: () => choice('get', 'set', 'async', 'await', 'static', 'export', 'let'),
1104
+
1105
+ _semicolon: ($) => choice($._automatic_semicolon, ';'),
1106
+ },
1107
+ });
1108
+
1109
+ /**
1110
+ * Creates a rule to match one or more of the rules separated by a comma
1111
+ *
1112
+ * @param {Rule} rule
1113
+ *
1114
+ * @returns {SeqRule}
1115
+ */
1116
+ function commaSep1(rule) {
1117
+ return seq(rule, repeat(seq(',', rule)));
1118
+ }
1119
+
1120
+ /**
1121
+ * Creates a rule to optionally match one or more of the rules separated by a comma
1122
+ *
1123
+ * @param {Rule} rule
1124
+ *
1125
+ * @returns {ChoiceRule}
1126
+ */
1127
+ function commaSep(rule) {
1128
+ return optional(commaSep1(rule));
1129
+ }