The ternary rule treats every ‘?’ as the start of a conditional
expression and waits for a matching ‘:’. Nullish coalescing (??)
therefore opens a meta.ternary-if.js scope that never closes,
corrupting highlighting for the remainder of the file (including
past </script> when the grammar is embedded in HTML).
Guard the ternary begin pattern so it no longer matches ?? or
optional chaining ?. — while still matching ‘a ?.5 : b’, where the
‘.’ belongs to the number — and scope the modern operators instead:
?? and ?. (ES2020), ??=/&&=/||= (ES2021), ** and **= (ES2016).
Also add numeric separators (1_000_000, ES2021), BigInt literals
(123n, 0xFFn, ES2020), and the regular expression flags s (ES2018),
d (ES2021) and v (ES2024).
The ternary rule treats every ? as the start of a conditional expression and waits for a : to close it. Nullish coalescing therefore opens a meta.ternary-if.js scope that never closes, corrupting highlighting for the rest of the file — including past </script> when the grammar is embedded in HTML:
Before (gtm scope output — note the two unclosed scopes swallowing the next line):
After:
Changes:
Verified by running TextMate's gtm parser over a test file covering each construct plus regressions (plain and nested ternaries, signed numbers, .5 literals).