Merge branch 'main' into add_vitest_support_to_js

This commit is contained in:
Sarthak Agarwal 2026-01-31 19:39:03 +05:30 committed by GitHub
commit 3e7be21e16
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 195 additions and 7 deletions

View file

@ -659,6 +659,19 @@ def _add_global_declarations_for_language(
# Get names of existing declarations # Get names of existing declarations
existing_names = {decl.name for decl in original_declarations} existing_names = {decl.name for decl in original_declarations}
# Also exclude names that are already imported (to avoid duplicating imported types)
original_imports = analyzer.find_imports(original_source)
for imp in original_imports:
# Add default import name
if imp.default_import:
existing_names.add(imp.default_import)
# Add named imports (use alias if present, otherwise use original name)
for name, alias in imp.named_imports:
existing_names.add(alias if alias else name)
# Add namespace import
if imp.namespace_import:
existing_names.add(imp.namespace_import)
# Find new declarations (names that don't exist in original) # Find new declarations (names that don't exist in original)
new_declarations = [] new_declarations = []
seen_sources = set() # Track to avoid duplicates from destructuring seen_sources = set() # Track to avoid duplicates from destructuring

View file

@ -294,10 +294,9 @@ def get_code_optimization_context_for_language(
helper_code = "\n\n".join(h.source_code for h in same_file_helpers) helper_code = "\n\n".join(h.source_code for h in same_file_helpers)
target_file_code = target_file_code + "\n\n" + helper_code target_file_code = target_file_code + "\n\n" + helper_code
# Add global variables (module-level declarations) referenced by the function and helpers # Note: code_context.read_only_context contains type definitions and global variables
# These should be included in read-writable context so AI can modify them if needed # These should be passed as read-only context to the AI, not prepended to the target code
if code_context.read_only_context: # If prepended to target code, the AI treats them as code to optimize and includes them in output
target_file_code = code_context.read_only_context + "\n\n" + target_file_code
# Add imports to target file code # Add imports to target file code
if imports_code: if imports_code:
@ -350,8 +349,9 @@ def get_code_optimization_context_for_language(
return CodeOptimizationContext( return CodeOptimizationContext(
testgen_context=testgen_context, testgen_context=testgen_context,
read_writable_code=read_writable_code, read_writable_code=read_writable_code,
# Global variables are now included in read-writable code, so don't duplicate in read-only # Pass type definitions and globals as read-only context for the AI
read_only_context_code="", # This way the AI sees them as context but doesn't include them in optimized output
read_only_context_code=code_context.read_only_context,
hashing_code_context=read_writable_code.flat, hashing_code_context=read_writable_code.flat,
hashing_code_context_hash=code_hash, hashing_code_context_hash=code_hash,
helper_functions=helper_function_sources, helper_functions=helper_function_sources,

View file

@ -47,7 +47,11 @@ try {
} }
// Configuration // Configuration
const MAX_BATCHES = parseInt(process.env.CODEFLASH_PERF_LOOP_COUNT || '10000', 10); const PERF_LOOP_COUNT = parseInt(process.env.CODEFLASH_PERF_LOOP_COUNT || '10000', 10);
const PERF_BATCH_SIZE = parseInt(process.env.CODEFLASH_PERF_BATCH_SIZE || '10', 10);
// MAX_BATCHES = how many batches needed to reach PERF_LOOP_COUNT iterations
// Add 1 to handle any rounding, but cap at PERF_LOOP_COUNT to avoid excessive batches
const MAX_BATCHES = Math.min(Math.ceil(PERF_LOOP_COUNT / PERF_BATCH_SIZE) + 1, PERF_LOOP_COUNT);
const TARGET_DURATION_MS = parseInt(process.env.CODEFLASH_PERF_TARGET_DURATION_MS || '10000', 10); const TARGET_DURATION_MS = parseInt(process.env.CODEFLASH_PERF_TARGET_DURATION_MS || '10000', 10);
const MIN_BATCHES = parseInt(process.env.CODEFLASH_PERF_MIN_LOOPS || '5', 10); const MIN_BATCHES = parseInt(process.env.CODEFLASH_PERF_MIN_LOOPS || '5', 10);

View file

@ -1893,3 +1893,174 @@ export class DataProcessor<T> {
} }
""" """
class TestImportedTypeNotDuplicated:
"""Tests to ensure imported types are not duplicated during code replacement.
When a type is already imported in the original file, it should NOT be
added as a new declaration from the optimized code, even if the optimized
code contains the type definition (because it was provided as context).
See: https://github.com/codeflash-ai/appsmith/pull/20
"""
def test_imported_interface_not_added_as_declaration(self, ts_support, temp_project):
"""Test that an imported interface is not duplicated in the output.
When TreeNode is imported from another file and the optimized code
contains the TreeNode interface definition (from read-only context),
the replacement should NOT add the interface to the original file.
"""
from codeflash.models.models import CodeStringsMarkdown, CodeString
# Original source imports TreeNode
original_source = """\
import type { TreeNode } from "./constants";
export function getNearestAbove(
tree: Record<string, TreeNode>,
effectedBoxId: string,
) {
const aboves = tree[effectedBoxId].aboves;
return aboves.reduce((prev: string[], next: string) => {
if (!prev[0]) return [next];
let nextBottomRow = tree[next].bottomRow;
let prevBottomRow = tree[prev[0]].bottomRow;
if (nextBottomRow > prevBottomRow) return [next];
return prev;
}, []);
}
"""
file_path = temp_project / "helpers.ts"
file_path.write_text(original_source, encoding="utf-8")
# Optimized code includes the TreeNode interface (from read-only context)
# This simulates what the AI might return when type definitions are included in context
optimized_code_with_interface = """\
interface TreeNode {
aboves: string[];
belows: string[];
topRow: number;
bottomRow: number;
}
export function getNearestAbove(
tree: Record<string, TreeNode>,
effectedBoxId: string,
) {
const aboves = tree[effectedBoxId].aboves;
return aboves.reduce((prev: string[], next: string) => {
if (!prev[0]) return [next];
// Optimized: cache lookups
const nextBottomRow = tree[next].bottomRow;
const prevBottomRow = tree[prev[0]].bottomRow;
return nextBottomRow > prevBottomRow ? [next] : prev;
}, []);
}
"""
code_markdown = CodeStringsMarkdown(
code_strings=[
CodeString(
code=optimized_code_with_interface,
file_path=Path("helpers.ts"),
language="typescript"
)
],
language="typescript"
)
replace_function_definitions_for_language(
["getNearestAbove"],
code_markdown,
file_path,
temp_project,
)
result = file_path.read_text()
# The TreeNode interface should NOT appear in the result
# (it's already imported, so adding it would cause a duplicate)
assert "interface TreeNode" not in result, (
f"TreeNode interface should NOT be added to the file since it's already imported.\n"
f"Result contains:\n{result}"
)
# The import should still be there
assert 'import type { TreeNode } from "./constants"' in result, (
f"Original import should be preserved.\nResult:\n{result}"
)
# The optimized function should be there
assert "// Optimized: cache lookups" in result, (
f"Optimized function should be in the result.\nResult:\n{result}"
)
# The result should be valid TypeScript
assert ts_support.validate_syntax(result) is True
def test_multiple_imported_types_not_duplicated(self, ts_support, temp_project):
"""Test that multiple imported types are not duplicated."""
from codeflash.models.models import CodeStringsMarkdown, CodeString
original_source = """\
import type { TreeNode, NodeSpace } from "./constants";
import { MAX_BOX_SIZE } from "./constants";
export function processNode(node: TreeNode, space: NodeSpace): number {
return node.topRow + space.top;
}
"""
file_path = temp_project / "processor.ts"
file_path.write_text(original_source, encoding="utf-8")
# Optimized code includes both interfaces
optimized_code = """\
interface TreeNode {
topRow: number;
bottomRow: number;
}
interface NodeSpace {
top: number;
bottom: number;
}
export function processNode(node: TreeNode, space: NodeSpace): number {
// Optimized
return (node.topRow + space.top) | 0;
}
"""
code_markdown = CodeStringsMarkdown(
code_strings=[
CodeString(
code=optimized_code,
file_path=Path("processor.ts"),
language="typescript"
)
],
language="typescript"
)
replace_function_definitions_for_language(
["processNode"],
code_markdown,
file_path,
temp_project,
)
result = file_path.read_text()
# Neither interface should be added
assert "interface TreeNode" not in result
assert "interface NodeSpace" not in result
# Imports should be preserved
assert 'import type { TreeNode, NodeSpace } from "./constants"' in result
# Optimized code should be there
assert "// Optimized" in result
assert ts_support.validate_syntax(result) is True