Skip to content

Commit eeeff25

Browse files
authored
Merge pull request #51 from qodex-ai/nodejs_esprima_version_fix
Nodejs esprima version fix
2 parents d0ee962 + 76b67cb commit eeeff25

3 files changed

Lines changed: 66 additions & 6 deletions

File tree

config.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ ignored_dirs:
1818
- downloads
1919
- eggs
2020
- .eggs
21-
- lib
2221
- lib64
2322
- parts
2423
- sdist

nodejs_pipeline/find_api_definition_files.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,17 @@
99
'api', 'endpoint', 'router', 'controller', 'middleware', 'rest'
1010
}
1111

12+
HTTP_METHODS = ['get', 'post', 'put', 'delete', 'patch', 'options', 'head']
13+
ROUTE_OBJECT_PREFIXES = ['app', 'router', 'route', 'api', 'controller', 'server']
14+
ROUTE_OBJECT_SUFFIXES = ['Router', 'Routes', 'Api', 'Controller', 'App', 'Server']
15+
16+
route_prefix_pattern = r'(?:' + '|'.join(ROUTE_OBJECT_PREFIXES) + r')'
17+
route_suffix_pattern = r'(?:[A-Za-z_$][\w$]*?(?:' + '|'.join(ROUTE_OBJECT_SUFFIXES) + r'))'
18+
route_object_pattern = r'(?:' + route_prefix_pattern + r'|' + route_suffix_pattern + r')'
19+
1220
# Regex patterns to detect API routes or decorators
1321
ROUTE_METHOD_PATTERN = re.compile(
14-
r'\b(app|router|route)\s*\.\s*(' + '|'.join(API_DECORATOR_NAMES) + r')\s*\(',
22+
r'\b' + route_object_pattern + r'\s*\.\s*(?:' + '|'.join(HTTP_METHODS) + r')\s*\(',
1523
re.IGNORECASE
1624
)
1725

nodejs_pipeline/identify_api_functions.py

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,71 @@
11
from pathlib import Path
22
import esprima
33
import json
4+
import re
45

56

6-
API_METHODS = {"get", "post", "put", "delete", "patch"}
7+
API_METHODS = {"get", "post", "put", "delete", "patch", "options", "head"}
8+
ROUTE_OBJECT_KEYWORDS = {"app", "router", "route", "api", "controller", "server"}
9+
ROUTE_OBJECT_SUFFIXES = ("router", "routes", "route", "app", "server", "controller", "api")
10+
OPTIONAL_CATCH_PATTERN = re.compile(r'catch\s*(\{)')
11+
FALLBACK_ENDPOINT_PATTERN = re.compile(
12+
r'(?P<object>[A-Za-z_$][\w$]*)\s*\.\s*(?P<method>GET|POST|PUT|DELETE|PATCH|OPTIONS|HEAD)\s*\(\s*(?P<route>["\'].*?["\'])?',
13+
re.IGNORECASE | re.DOTALL
14+
)
15+
16+
17+
def _parse_with_optional_catch_fallback(source, *, loc=True):
18+
"""
19+
Attempt to parse JavaScript source. If the parser fails because of
20+
optional catch binding syntax (catch { ... }), rewrite those blocks
21+
to catch (__apimesh_err) { ... } and retry once.
22+
"""
23+
try:
24+
return esprima.parseModule(source, loc=loc)
25+
except Exception as first_error:
26+
patched_source, replaced = OPTIONAL_CATCH_PATTERN.subn('catch (__apimesh_err) {', source)
27+
if not replaced:
28+
raise first_error
29+
try:
30+
return esprima.parseModule(patched_source, loc=loc)
31+
except Exception:
32+
raise first_error
33+
34+
35+
def _extract_endpoints_with_regex(source: str, file_path: Path):
36+
"""Fallback endpoint detector when esprima cannot parse the file."""
37+
endpoints = []
38+
for match in FALLBACK_ENDPOINT_PATTERN.finditer(source):
39+
method = match.group('method').upper()
40+
route_literal = match.group('route')
41+
route = None
42+
if route_literal and len(route_literal) >= 2:
43+
route = route_literal[1:-1]
44+
start = match.start()
45+
end = match.end()
46+
start_line = source.count('\n', 0, start) + 1
47+
end_line = source.count('\n', 0, end) + 1
48+
obj = match.group('object') or ""
49+
low = obj.lower()
50+
if not (low in ROUTE_OBJECT_KEYWORDS or any(low.endswith(suf) for suf in ROUTE_OBJECT_SUFFIXES) or low.startswith(('app', 'api'))):
51+
continue
52+
endpoints.append({
53+
"type": "function",
54+
"method": method,
55+
"route": route,
56+
"start_line": start_line,
57+
"end_line": end_line,
58+
"file_path": str(file_path)
59+
})
60+
return endpoints
761

862

963
def find_api_endpoints_js(file_path: Path):
1064
try:
1165
source = file_path.read_text(encoding='utf-8')
12-
tree = esprima.parseModule(source, loc=True) # loc=True gives line numbers
66+
tree = _parse_with_optional_catch_fallback(source, loc=True)
1367
except Exception as e:
14-
print(f"Error parsing {file_path}: {e}")
15-
return []
68+
return _extract_endpoints_with_regex(source, file_path)
1669

1770
endpoints = []
1871

0 commit comments

Comments
 (0)