Skip to content

Commit 77d9f4f

Browse files
authored
Merge branch 'main' into fix-opt-review
2 parents 9700b7e + e8989c2 commit 77d9f4f

5 files changed

Lines changed: 74 additions & 10 deletions

File tree

codeflash/discovery/functions_to_optimize.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,32 @@ def get_files_for_language(
216216
return files
217217

218218

219+
def _is_js_ts_function_exported(file_path: Path, function_name: str) -> tuple[bool, str | None]:
220+
"""Check if a JavaScript/TypeScript function is exported from its module.
221+
222+
For JS/TS, functions that are not exported cannot be imported by tests,
223+
making them impossible to optimize.
224+
225+
Args:
226+
file_path: Path to the source file.
227+
function_name: Name of the function to check.
228+
229+
Returns:
230+
Tuple of (is_exported, export_name). export_name may be 'default' for default exports.
231+
232+
"""
233+
from codeflash.languages.treesitter_utils import get_analyzer_for_file
234+
235+
try:
236+
source = file_path.read_text(encoding="utf-8")
237+
analyzer = get_analyzer_for_file(file_path)
238+
return analyzer.is_function_exported(source, function_name)
239+
except Exception as e:
240+
logger.debug(f"Failed to check export status for {function_name}: {e}")
241+
# Return True to avoid blocking in case of errors
242+
return True, None
243+
244+
219245
def _find_all_functions_in_python_file(file_path: Path) -> dict[Path, list[FunctionToOptimize]]:
220246
"""Find all optimizable functions in a Python file using AST parsing.
221247
@@ -338,6 +364,36 @@ def get_functions_to_optimize(
338364
exit_with_message(
339365
f"Function {only_get_this_function} not found in file {file}\nor the function does not have a 'return' statement or is a property"
340366
)
367+
368+
# For JavaScript/TypeScript, verify that the function (or its parent class) is exported
369+
# Non-exported functions cannot be imported by tests
370+
if found_function.language in ("javascript", "typescript"):
371+
# For class methods, check if the parent class is exported
372+
# For standalone functions, check if the function itself is exported
373+
if found_function.parents:
374+
# It's a class method - check if the class is exported
375+
name_to_check = found_function.top_level_parent_name
376+
else:
377+
# It's a standalone function - check if the function is exported
378+
name_to_check = found_function.function_name
379+
380+
is_exported, export_name = _is_js_ts_function_exported(file, name_to_check)
381+
if not is_exported:
382+
if found_function.parents:
383+
logger.debug(
384+
f"Class '{name_to_check}' containing method '{found_function.function_name}' "
385+
f"is not exported from {file}. "
386+
f"In JavaScript/TypeScript, only exported classes/functions can be optimized "
387+
f"because tests need to import them."
388+
)
389+
else:
390+
logger.debug(
391+
f"Function '{found_function.function_name}' is not exported from {file}. "
392+
f"In JavaScript/TypeScript, only exported functions can be optimized because "
393+
f"tests need to import them."
394+
)
395+
return {}, 0, None
396+
341397
functions[file] = [found_function]
342398
else:
343399
logger.info("Finding all functions modified in the current git diff ...")

codeflash/languages/javascript/module_system.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,18 @@ def _get_relative_import_path(target_path: Path, source_path: Path) -> str:
184184

185185

186186
def add_js_extension(module_path: str) -> str:
187-
"""Add .js extension to relative module paths for ESM compatibility."""
188-
if module_path.startswith(("./", "../")):
189-
if not module_path.endswith(".js") and not module_path.endswith(".mjs"):
190-
return module_path + ".js"
187+
"""Process module path for ESM compatibility.
188+
189+
NOTE: This function intentionally does NOT add extensions because:
190+
1. TypeScript projects resolve modules without explicit extensions
191+
2. Adding .js to .ts imports causes "Cannot find module" errors
192+
3. Modern bundlers (webpack, vite, etc.) handle extension resolution automatically
193+
194+
The function name is preserved for backward compatibility but the behavior
195+
has been changed to NOT add extensions.
196+
"""
197+
# Previously this function added .js extensions, but this caused module resolution
198+
# errors in TypeScript projects. We now preserve paths without adding extensions.
191199
return module_path
192200

193201

codeflash/verification/verifier.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def generate_tests(
7575
func_name = function_to_optimize.function_name
7676
qualified_name = function_to_optimize.qualified_name
7777

78-
# First validate and fix import styles
78+
# Validate and fix import styles (default vs named exports)
7979
generated_test_source = validate_and_fix_import_style(generated_test_source, source_file, func_name)
8080

8181
# Convert module system if needed (e.g., CommonJS -> ESM for ESM projects)

tests/test_javascript_function_discovery.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -346,11 +346,11 @@ def test_get_specific_function(self, tmp_path):
346346
"""Test getting a specific function by name."""
347347
js_file = tmp_path / "math_utils.js"
348348
js_file.write_text("""
349-
function add(a, b) {
349+
export function add(a, b) {
350350
return a + b;
351351
}
352352
353-
function subtract(a, b) {
353+
export function subtract(a, b) {
354354
return a - b;
355355
}
356356
""")
@@ -378,7 +378,7 @@ def test_get_class_method(self, tmp_path):
378378
"""Test getting a specific class method."""
379379
js_file = tmp_path / "calculator.js"
380380
js_file.write_text("""
381-
class Calculator {
381+
export class Calculator {
382382
add(a, b) {
383383
return a + b;
384384
}
@@ -388,7 +388,7 @@ class Calculator {
388388
}
389389
}
390390
391-
function standaloneFunc() {
391+
export function standaloneFunc() {
392392
return 42;
393393
}
394394
""")

tests/test_languages/test_javascript_instrumentation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,4 +651,4 @@ def test_this_method_call_exact_output(self):
651651

652652
expected = " return codeflash.capture('Class.fibonacci', '1', this.fibonacci.bind(this), n - 1);"
653653
assert transformed == expected, f"Expected:\n{expected}\nGot:\n{transformed}"
654-
assert counter == 1
654+
assert counter == 1

0 commit comments

Comments
 (0)