22
33import io .github .randomcodespace .iq .detector .DetectorContext ;
44import io .github .randomcodespace .iq .detector .DetectorResult ;
5- import io .github .randomcodespace .iq .grammar .javascript .JavaScriptParser ;
6- import io .github .randomcodespace .iq .grammar .javascript .JavaScriptParserBaseListener ;
75import io .github .randomcodespace .iq .model .CodeNode ;
86import io .github .randomcodespace .iq .model .NodeKind ;
9- import org .antlr .v4 .runtime .tree .ParseTree ;
10- import org .antlr .v4 .runtime .tree .ParseTreeWalker ;
117import org .springframework .stereotype .Component ;
128
139import java .util .ArrayList ;
1410import java .util .List ;
15- import java .util .Set ;
1611import java .util .regex .Matcher ;
1712import java .util .regex .Pattern ;
1813import io .github .randomcodespace .iq .detector .DetectorInfo ;
3025@ Component
3126public class ExpressRouteDetector extends AbstractTypeScriptDetector {
3227
33- private static final Set <String > HTTP_METHODS = Set .of (
34- "get" , "post" , "put" , "delete" , "patch" , "options" , "head" , "all"
35- );
36-
3728 private static final Pattern ROUTE_PATTERN = Pattern .compile (
3829 "(\\ w+)\\ .(get|post|put|delete|patch|options|head|all)\\ (\\ s*['\" `]([^'\" `]+)['\" `]"
3930 );
@@ -43,53 +34,6 @@ public String getName() {
4334 return "typescript.express_routes" ;
4435 }
4536
46-
47- @ Override
48- protected DetectorResult detectWithAst (ParseTree tree , DetectorContext ctx ) {
49- List <CodeNode > nodes = new ArrayList <>();
50- String filePath = ctx .filePath ();
51- String moduleName = ctx .moduleName ();
52-
53- ParseTreeWalker .DEFAULT .walk (new JavaScriptParserBaseListener () {
54- @ Override
55- public void enterArgumentsExpression (JavaScriptParser .ArgumentsExpressionContext argCtx ) {
56- // Look for: expr.method(args) where method is an HTTP method
57- if (argCtx .singleExpression () instanceof JavaScriptParser .MemberDotExpressionContext memberCtx ) {
58- String methodName = memberCtx .identifierName ().getText ();
59- if (!HTTP_METHODS .contains (methodName )) return ;
60-
61- String routerName = extractIdentifierText (memberCtx .singleExpression ());
62- if (routerName == null ) return ;
63-
64- // Get the first string argument (the path)
65- String path = extractFirstStringArg (argCtx .arguments ());
66- if (path == null ) return ;
67-
68- String method = methodName .toUpperCase ();
69- int line = lineOf (argCtx );
70-
71- String nodeId = "endpoint:" + (moduleName != null ? moduleName : "" ) + ":" + method + ":" + path ;
72- CodeNode node = new CodeNode ();
73- node .setId (nodeId );
74- node .setKind (NodeKind .ENDPOINT );
75- node .setLabel (method + " " + path );
76- node .setFqn (filePath + "::" + method + ":" + path );
77- node .setModule (moduleName );
78- node .setFilePath (filePath );
79- node .setLineStart (line );
80- node .getProperties ().put ("protocol" , "REST" );
81- node .getProperties ().put ("http_method" , method );
82- node .getProperties ().put ("path_pattern" , path );
83- node .getProperties ().put ("framework" , "express" );
84- node .getProperties ().put ("router" , routerName );
85- nodes .add (node );
86- }
87- }
88- }, tree );
89-
90- return DetectorResult .of (nodes , List .of ());
91- }
92-
9337 @ Override
9438 protected DetectorResult detectWithRegex (DetectorContext ctx ) {
9539 List <CodeNode > nodes = new ArrayList <>();
@@ -124,44 +68,4 @@ protected DetectorResult detectWithRegex(DetectorContext ctx) {
12468
12569 return DetectorResult .of (nodes , List .of ());
12670 }
127-
128- /** Extract a simple identifier name from a single expression, or null. */
129- static String extractIdentifierText (JavaScriptParser .SingleExpressionContext expr ) {
130- if (expr instanceof JavaScriptParser .IdentifierExpressionContext idCtx ) {
131- return idCtx .getText ();
132- }
133- // For chained access like `this.app`, return the whole text
134- if (expr instanceof JavaScriptParser .MemberDotExpressionContext memberCtx ) {
135- return memberCtx .getText ();
136- }
137- return expr != null ? expr .getText () : null ;
138- }
139-
140- /** Extract the first string literal argument from an arguments context. */
141- static String extractFirstStringArg (JavaScriptParser .ArgumentsContext args ) {
142- if (args == null || args .argument () == null || args .argument ().isEmpty ()) return null ;
143- var firstArg = args .argument (0 );
144- if (firstArg == null || firstArg .singleExpression () == null ) return null ;
145- var expr = firstArg .singleExpression ();
146- return extractStringLiteral (expr );
147- }
148-
149- /** Extract a string literal value (strip quotes) from a single expression. */
150- static String extractStringLiteral (JavaScriptParser .SingleExpressionContext expr ) {
151- if (expr instanceof JavaScriptParser .LiteralExpressionContext litCtx ) {
152- var literal = litCtx .literal ();
153- if (literal != null && literal .StringLiteral () != null ) {
154- String raw = literal .StringLiteral ().getText ();
155- return raw .substring (1 , raw .length () - 1 );
156- }
157- }
158- // Handle template strings (backtick with no expressions)
159- if (expr instanceof JavaScriptParser .TemplateStringExpressionContext ) {
160- String raw = expr .getText ();
161- if (raw .startsWith ("`" ) && raw .endsWith ("`" )) {
162- return raw .substring (1 , raw .length () - 1 );
163- }
164- }
165- return null ;
166- }
16771}
0 commit comments