Merge branch 'main' into add_vitest_support_to_js
This commit is contained in:
commit
3e7be21e16
4 changed files with 195 additions and 7 deletions
|
|
@ -659,6 +659,19 @@ def _add_global_declarations_for_language(
|
|||
# Get names of existing 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)
|
||||
new_declarations = []
|
||||
seen_sources = set() # Track to avoid duplicates from destructuring
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
target_file_code = target_file_code + "\n\n" + helper_code
|
||||
|
||||
# Add global variables (module-level declarations) referenced by the function and helpers
|
||||
# These should be included in read-writable context so AI can modify them if needed
|
||||
if code_context.read_only_context:
|
||||
target_file_code = code_context.read_only_context + "\n\n" + target_file_code
|
||||
# Note: code_context.read_only_context contains type definitions and global variables
|
||||
# These should be passed as read-only context to the AI, not prepended to the target code
|
||||
# If prepended to target code, the AI treats them as code to optimize and includes them in output
|
||||
|
||||
# Add imports to target file code
|
||||
if imports_code:
|
||||
|
|
@ -350,8 +349,9 @@ def get_code_optimization_context_for_language(
|
|||
return CodeOptimizationContext(
|
||||
testgen_context=testgen_context,
|
||||
read_writable_code=read_writable_code,
|
||||
# Global variables are now included in read-writable code, so don't duplicate in read-only
|
||||
read_only_context_code="",
|
||||
# Pass type definitions and globals as read-only context for the AI
|
||||
# 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_hash=code_hash,
|
||||
helper_functions=helper_function_sources,
|
||||
|
|
|
|||
|
|
@ -47,7 +47,11 @@ try {
|
|||
}
|
||||
|
||||
// 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 MIN_BATCHES = parseInt(process.env.CODEFLASH_PERF_MIN_LOOPS || '5', 10);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue