Skip to content

JS nullish coalescing and optional chaining operators break syntax highlighting on GitHub #5118

Open
@FeBe95

Description

Vue - Official extension or vue-tsc version

N/A

VSCode version

N/A

Vue version

N/A

TypeScript version

N/A

System Info

No response

package.json dependencies

No response

Steps to reproduce

I've noticed that using ?? and/or ?. inside of a <script> tag breaks syntax highlighting on GitHub.

Note

GitHub is using this repository for its syntax highlighting since end of last year:

Examples

  • Closing tag of script element is highlighted incorrectly when using nullish coalescing operator ??:
    <script>
    let foo = bar ?? baz;
    </script>
  • Closing tag of script element is highlighted incorrectly when using optional chaining operator ?.:
    <script>
    let foo = bar?.baz;
    </script>
  • Closing tag of script element is highlighted correctly when using logical OR ||:
    <script>
    let foo = bar || baz;
    </script>

What is expected?

Code is highlighted correctly.

What is actually happening?

Code is not highlighted correctly, or not even highlighted at all.

Link to minimal reproduction

No response

Any additional comments?

This bug is the potentially causing another issue on GitHub, where syntax highlighting is completely absent for larger files that contain these operators. I've tracked it down to be caused from a certain amount of statements containing any of the two operators in combination with surrounding parentheses.

I guess there might be some syntax analysis depth limit being hit, because the operators are not parsed correctly (causing some kind of nesting where there should be none).

The following table demonstrates this (secondary) issue:

# Highlighting mostly working,
closing tag highlighted incorrectly,
(using 84x ??)
No highlighting at all
(using 85x ??)
Correct highlighting
(using 85x ||)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<script>
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
// foo = (bar ?? 'bar');
</script>
<script>
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
foo = (bar ?? 'bar');
</script>
<script>
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
foo = (bar || 'bar');
</script>

Note:

You can observe a similar "syntax analysis depth limit" when nesting if statements. In this case 253 nested if statements are highlighted correctly, while 254 nested if statements are not highlighted at all (I made sure to break the statements into multiple lines, so that the single-line length limit of 1024 is not being hit).

<script>
if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) {
if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) {
if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) {
if (true) {
  // foo
}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
}
</script>
<script>
if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) {
if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) {
if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) { if (true) {
if (true) { if (true) {
  // foo
}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
}}
</script>

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions