Skip to content

Commit f95bc54

Browse files
aksOpsclaude
andcommitted
Add dedicated TypeScript ANTLR grammar for TS-specific syntax detection
Adds the TypeScript grammar from antlr/grammars-v4 (MIT License) which supports decorators, type annotations, interfaces, generics, enums, and namespaces. Updates AntlrParserFactory to route TypeScript to its own parser instead of sharing the JavaScript grammar. Updates TypeScriptStructuresDetector to use ANTLR AST walking with regex fallback (picks whichever finds more structures). Updates NestJSControllerDetector to warm the TS parse cache for shared use. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 89c0f43 commit f95bc54

7 files changed

Lines changed: 1806 additions & 9 deletions

File tree

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2014 by Bart Kiers (original author) and Alexandre Vitorelli (contributor -> ported to CSharp)
5+
* Copyright (c) 2017 by Ivan Kochurkin (Positive Technologies):
6+
added ECMAScript 6 support, cleared and transformed to the universal grammar.
7+
* Copyright (c) 2018 by Juan Alvarez (contributor -> ported to Go)
8+
* Copyright (c) 2019 by Andrii Artiushok (contributor -> added TypeScript support)
9+
* Copyright (c) 2024 by Andrew Leppard (www.wegrok.review)
10+
*
11+
* Permission is hereby granted, free of charge, to any person
12+
* obtaining a copy of this software and associated documentation
13+
* files (the "Software"), to deal in the Software without
14+
* restriction, including without limitation the rights to use,
15+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
16+
* copies of the Software, and to permit persons to whom the
17+
* Software is furnished to do so, subject to the following
18+
* conditions:
19+
*
20+
* The above copyright notice and this permission notice shall be
21+
* included in all copies or substantial portions of the Software.
22+
*
23+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
25+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
27+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
28+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30+
* OTHER DEALINGS IN THE SOFTWARE.
31+
*/
32+
33+
// $antlr-format alignTrailingComments true, columnLimit 150, maxEmptyLinesToKeep 1, reflowComments false, useTab false
34+
// $antlr-format allowShortRulesOnASingleLine true, allowShortBlocksOnASingleLine true, minEmptyLines 0, alignSemicolons ownLine
35+
// $antlr-format alignColons trailing, singleLineOverrulesHangingColon true, alignLexerCommands true, alignLabels true, alignTrailers true
36+
37+
lexer grammar TypeScriptLexer;
38+
39+
channels {
40+
ERROR
41+
}
42+
43+
options {
44+
superClass = TypeScriptLexerBase;
45+
}
46+
47+
MultiLineComment : '/*' .*? '*/' -> channel(HIDDEN);
48+
SingleLineComment : '//' ~[\r\n\u2028\u2029]* -> channel(HIDDEN);
49+
RegularExpressionLiteral:
50+
'/' RegularExpressionFirstChar RegularExpressionChar* {this.IsRegexPossible()}? '/' IdentifierPart*
51+
;
52+
53+
OpenBracket : '[';
54+
CloseBracket : ']';
55+
OpenParen : '(';
56+
CloseParen : ')';
57+
OpenBrace : '{' {this.ProcessOpenBrace();};
58+
TemplateCloseBrace : {this.IsInTemplateString()}? '}' -> popMode;
59+
CloseBrace : '}' {this.ProcessCloseBrace();};
60+
SemiColon : ';';
61+
Comma : ',';
62+
Assign : '=';
63+
QuestionMark : '?';
64+
QuestionMarkDot : '?.';
65+
Colon : ':';
66+
Ellipsis : '...';
67+
Dot : '.';
68+
PlusPlus : '++';
69+
MinusMinus : '--';
70+
Plus : '+';
71+
Minus : '-';
72+
BitNot : '~';
73+
Not : '!';
74+
Multiply : '*';
75+
Divide : '/';
76+
Modulus : '%';
77+
Power : '**';
78+
NullCoalesce : '??';
79+
Hashtag : '#';
80+
LeftShiftArithmetic : '<<';
81+
// We can't match these in the lexer because it would cause issues when parsing
82+
// types like Map<string, Map<string, string>>
83+
// RightShiftArithmetic : '>>';
84+
// RightShiftLogical : '>>>';
85+
LessThan : '<';
86+
MoreThan : '>';
87+
LessThanEquals : '<=';
88+
GreaterThanEquals : '>=';
89+
Equals_ : '==';
90+
NotEquals : '!=';
91+
IdentityEquals : '===';
92+
IdentityNotEquals : '!==';
93+
BitAnd : '&';
94+
BitXOr : '^';
95+
BitOr : '|';
96+
And : '&&';
97+
Or : '||';
98+
MultiplyAssign : '*=';
99+
DivideAssign : '/=';
100+
ModulusAssign : '%=';
101+
PlusAssign : '+=';
102+
MinusAssign : '-=';
103+
LeftShiftArithmeticAssign : '<<=';
104+
RightShiftArithmeticAssign : '>>=';
105+
RightShiftLogicalAssign : '>>>=';
106+
BitAndAssign : '&=';
107+
BitXorAssign : '^=';
108+
BitOrAssign : '|=';
109+
PowerAssign : '**=';
110+
NullishCoalescingAssign : '??=';
111+
ARROW : '=>';
112+
113+
/// Null Literals
114+
115+
NullLiteral: 'null';
116+
117+
/// Boolean Literals
118+
119+
BooleanLiteral: 'true' | 'false';
120+
121+
/// Numeric Literals
122+
123+
DecimalLiteral:
124+
DecimalIntegerLiteral '.' [0-9] [0-9_]* ExponentPart?
125+
| '.' [0-9] [0-9_]* ExponentPart?
126+
| DecimalIntegerLiteral ExponentPart?
127+
;
128+
129+
/// Numeric Literals
130+
131+
HexIntegerLiteral : '0' [xX] [0-9a-fA-F] HexDigit*;
132+
OctalIntegerLiteral : '0' [0-7]+ {!this.IsStrictMode()}?;
133+
OctalIntegerLiteral2 : '0' [oO] [0-7] [_0-7]*;
134+
BinaryIntegerLiteral : '0' [bB] [01] [_01]*;
135+
136+
BigHexIntegerLiteral : '0' [xX] [0-9a-fA-F] HexDigit* 'n';
137+
BigOctalIntegerLiteral : '0' [oO] [0-7] [_0-7]* 'n';
138+
BigBinaryIntegerLiteral : '0' [bB] [01] [_01]* 'n';
139+
BigDecimalIntegerLiteral : DecimalIntegerLiteral 'n';
140+
141+
/// Keywords
142+
143+
Break : 'break';
144+
Do : 'do';
145+
Instanceof : 'instanceof';
146+
Typeof : 'typeof';
147+
Case : 'case';
148+
Else : 'else';
149+
New : 'new';
150+
Var : 'var';
151+
Catch : 'catch';
152+
Finally : 'finally';
153+
Return : 'return';
154+
Void : 'void';
155+
Continue : 'continue';
156+
For : 'for';
157+
Switch : 'switch';
158+
While : 'while';
159+
Debugger : 'debugger';
160+
Function_ : 'function';
161+
This : 'this';
162+
With : 'with';
163+
Default : 'default';
164+
If : 'if';
165+
Throw : 'throw';
166+
Delete : 'delete';
167+
In : 'in';
168+
Try : 'try';
169+
As : 'as';
170+
From : 'from';
171+
ReadOnly : 'readonly';
172+
Async : 'async';
173+
Await : 'await';
174+
Yield : 'yield';
175+
YieldStar : 'yield*';
176+
177+
/// Future Reserved Words
178+
179+
Class : 'class';
180+
Enum : 'enum';
181+
Extends : 'extends';
182+
Super : 'super';
183+
Const : 'const';
184+
Export : 'export';
185+
Import : 'import';
186+
187+
/// The following tokens are also considered to be FutureReservedWords
188+
/// when parsing strict mode
189+
190+
Implements : 'implements';
191+
Let : 'let';
192+
Private : 'private';
193+
Public : 'public';
194+
Interface : 'interface';
195+
Package : 'package';
196+
Protected : 'protected';
197+
Static : 'static';
198+
199+
//keywords:
200+
Any : 'any';
201+
Number : 'number';
202+
Never : 'never';
203+
Boolean : 'boolean';
204+
String : 'string';
205+
Unique : 'unique';
206+
Symbol : 'symbol';
207+
Undefined : 'undefined';
208+
Object : 'object';
209+
210+
Of : 'of';
211+
KeyOf : 'keyof';
212+
213+
TypeAlias: 'type';
214+
215+
Constructor : 'constructor';
216+
Namespace : 'namespace';
217+
Require : 'require';
218+
Module : 'module';
219+
Declare : 'declare';
220+
221+
Abstract: 'abstract';
222+
223+
Is: 'is';
224+
225+
//
226+
// Ext.2 Additions to 1.8: Decorators
227+
//
228+
At: '@';
229+
230+
/// Identifier Names and Identifiers
231+
232+
Identifier: IdentifierStart IdentifierPart*;
233+
234+
/// String Literals
235+
StringLiteral:
236+
('"' DoubleStringCharacter* '"' | '\'' SingleStringCharacter* '\'') {this.ProcessStringLiteral();}
237+
;
238+
239+
BackTick: '`' {this.IncreaseTemplateDepth();} -> pushMode(TEMPLATE);
240+
241+
WhiteSpaces: [\t\u000B\u000C\u0020\u00A0]+ -> channel(HIDDEN);
242+
243+
LineTerminator: [\r\n\u2028\u2029] -> channel(HIDDEN);
244+
245+
/// Comments
246+
247+
HtmlComment : '<!--' .*? '-->' -> channel(HIDDEN);
248+
CDataComment : '<![CDATA[' .*? ']]>' -> channel(HIDDEN);
249+
UnexpectedCharacter : . -> channel(ERROR);
250+
251+
mode TEMPLATE;
252+
253+
TemplateStringEscapeAtom : '\\' .;
254+
BackTickInside : '`' {this.DecreaseTemplateDepth();} -> type(BackTick), popMode;
255+
TemplateStringStartExpression : '${' {this.StartTemplateString();} -> pushMode(DEFAULT_MODE);
256+
TemplateStringAtom : ~[`\\];
257+
258+
// Fragment rules
259+
260+
fragment DoubleStringCharacter: ~["\\\r\n] | '\\' EscapeSequence | LineContinuation;
261+
262+
fragment SingleStringCharacter: ~['\\\r\n] | '\\' EscapeSequence | LineContinuation;
263+
264+
fragment EscapeSequence:
265+
CharacterEscapeSequence
266+
| '0' // no digit ahead! TODO
267+
| HexEscapeSequence
268+
| UnicodeEscapeSequence
269+
| ExtendedUnicodeEscapeSequence
270+
;
271+
272+
fragment CharacterEscapeSequence: SingleEscapeCharacter | NonEscapeCharacter;
273+
274+
fragment HexEscapeSequence: 'x' HexDigit HexDigit;
275+
276+
fragment UnicodeEscapeSequence:
277+
'u' HexDigit HexDigit HexDigit HexDigit
278+
| 'u' '{' HexDigit HexDigit+ '}'
279+
;
280+
281+
fragment ExtendedUnicodeEscapeSequence: 'u' '{' HexDigit+ '}';
282+
283+
fragment SingleEscapeCharacter: ['"\\bfnrtv];
284+
285+
fragment NonEscapeCharacter: ~['"\\bfnrtv0-9xu\r\n];
286+
287+
fragment EscapeCharacter: SingleEscapeCharacter | [0-9] | [xu];
288+
289+
fragment LineContinuation: '\\' [\r\n\u2028\u2029]+;
290+
291+
fragment HexDigit: [_0-9a-fA-F];
292+
293+
fragment DecimalIntegerLiteral: '0' | [1-9] [0-9_]*;
294+
295+
fragment ExponentPart: [eE] [+-]? [0-9_]+;
296+
297+
fragment IdentifierPart: IdentifierStart | [\p{Mn}] | [\p{Nd}] | [\p{Pc}] | '\u200C' | '\u200D';
298+
299+
fragment IdentifierStart: [\p{L}] | [$_] | '\\' UnicodeEscapeSequence;
300+
301+
fragment RegularExpressionFirstChar:
302+
~[*\r\n\u2028\u2029\\/[]
303+
| RegularExpressionBackslashSequence
304+
| '[' RegularExpressionClassChar* ']'
305+
;
306+
307+
fragment RegularExpressionChar:
308+
~[\r\n\u2028\u2029\\/[]
309+
| RegularExpressionBackslashSequence
310+
| '[' RegularExpressionClassChar* ']'
311+
;
312+
313+
fragment RegularExpressionClassChar: ~[\r\n\u2028\u2029\]\\] | RegularExpressionBackslashSequence;
314+
315+
fragment RegularExpressionBackslashSequence: '\\' ~[\r\n\u2028\u2029];

0 commit comments

Comments
 (0)