Install cli post cloning in npm

This commit is contained in:
Sarthak Agarwal 2026-02-11 00:10:08 +05:30
parent 6428a22eba
commit 0b611c722a
2 changed files with 192 additions and 21 deletions

View file

@ -106,40 +106,63 @@ function installUv() {
}
}
/**
* Check if git is available
*/
function hasGit() {
try {
const result = spawnSync('git', ['--version'], {
stdio: 'ignore',
shell: true,
});
return result.status === 0;
} catch {
return false;
}
}
/**
* Install codeflash Python CLI using uv tool
*
* Installation priority:
* 1. GitHub main branch (if git available) - gets latest features
* 2. PyPI (fallback) - stable release
*
* We prefer GitHub because it has the latest JS/TS support that may not
* be published to PyPI yet. uv handles cloning internally in its cache.
*/
function installCodeflash(uvBin) {
logStep('2/3', 'Installing codeflash Python CLI...');
const GITHUB_REPO = 'git+https://github.com/codeflash-ai/codeflash.git';
// Priority 1: Install from GitHub (latest features, requires git)
if (hasGit()) {
try {
execSync(`"${uvBin}" tool install --force --python python3.12 "${GITHUB_REPO}"`, {
stdio: 'inherit',
shell: true,
});
logSuccess('codeflash CLI installed from GitHub (latest)');
return true;
} catch (error) {
logWarning(`GitHub installation failed: ${error.message}`);
logWarning('Falling back to PyPI...');
}
} else {
logWarning('Git not found, installing from PyPI...');
}
// Priority 2: Install from PyPI (stable release fallback)
try {
// Use uv tool install to install codeflash in an isolated environment
// This avoids conflicts with any existing Python environments
execSync(`"${uvBin}" tool install --force --python python3.12 codeflash`, {
stdio: 'inherit',
shell: true,
});
logSuccess('codeflash CLI installed successfully');
logSuccess('codeflash CLI installed from PyPI');
return true;
} catch (error) {
// If codeflash is not on PyPI yet, try installing from the local package
logWarning('codeflash not found on PyPI, trying local installation...');
try {
// Try installing from the current codeflash repo if we're in development
const cliRoot = path.resolve(__dirname, '..', '..', '..');
const pyprojectPath = path.join(cliRoot, 'pyproject.toml');
if (fs.existsSync(pyprojectPath)) {
execSync(`"${uvBin}" tool install --force "${cliRoot}"`, {
stdio: 'inherit',
shell: true,
});
logSuccess('codeflash CLI installed from local source');
return true;
}
} catch (localError) {
logError(`Failed to install codeflash: ${localError.message}`);
}
logError(`Failed to install codeflash: ${error.message}`);
return false;
}
}

View file

@ -545,3 +545,151 @@ function identity<T>(value: T): T {
assert len(functions) == 1
assert functions[0].name == "identity"
class TestExportConstArrowFunctions:
"""Tests for export const arrow function pattern - Issue #10.
Modern TypeScript codebases commonly use:
- export const slugify = (str: string) => { return s; }
- export const uniqueBy = <T>(array: T[]) => { ... }
These must be correctly recognized as optimizable functions.
"""
@pytest.fixture
def ts_analyzer(self):
"""Create a TypeScript analyzer."""
return TreeSitterAnalyzer(TreeSitterLanguage.TYPESCRIPT)
def test_export_const_arrow_function_basic(self, ts_analyzer):
"""Test finding export const arrow function (basic pattern)."""
code = """export const slugify = (str: string) => {
return str.toLowerCase();
};"""
functions = ts_analyzer.find_functions(code)
assert len(functions) == 1
assert functions[0].name == "slugify"
assert functions[0].is_arrow is True
assert ts_analyzer.has_return_statement(functions[0], code) is True
def test_export_const_arrow_function_optional_param(self, ts_analyzer):
"""Test finding export const arrow function with optional parameter."""
code = """export const slugify = (str: string, forDisplayingInput?: boolean) => {
if (!str) {
return "";
}
const s = str.toLowerCase();
return forDisplayingInput ? s : s.replace(/-+$/, "");
};"""
functions = ts_analyzer.find_functions(code)
assert len(functions) == 1
assert functions[0].name == "slugify"
assert functions[0].is_arrow is True
assert ts_analyzer.has_return_statement(functions[0], code) is True
def test_export_const_generic_arrow_function(self, ts_analyzer):
"""Test finding export const arrow function with generics."""
code = """export const uniqueBy = <T extends { [key: string]: unknown }>(array: T[], keys: (keyof T)[]) => {
return array.filter(
(item, index, self) => index === self.findIndex((t) => keys.every((key) => t[key] === item[key]))
);
};"""
functions = ts_analyzer.find_functions(code)
# Should find uniqueBy, and possibly the inner arrow functions
uniqueBy = next((f for f in functions if f.name == "uniqueBy"), None)
assert uniqueBy is not None
assert uniqueBy.is_arrow is True
assert ts_analyzer.has_return_statement(uniqueBy, code) is True
def test_export_const_arrow_function_is_exported(self, ts_analyzer):
"""Test that export const arrow functions are recognized as exported."""
code = """export const slugify = (str: string) => {
return str.toLowerCase();
};"""
# Check is_function_exported
is_exported, export_name = ts_analyzer.is_function_exported(code, "slugify")
assert is_exported is True
assert export_name == "slugify"
def test_export_const_with_default_export(self, ts_analyzer):
"""Test export const with separate default export."""
code = """export const slugify = (str: string) => {
return str.toLowerCase();
};
export default slugify;"""
functions = ts_analyzer.find_functions(code)
assert len(functions) == 1
assert functions[0].name == "slugify"
# Should be exported both ways
is_named, named_name = ts_analyzer.is_function_exported(code, "slugify")
assert is_named is True
def test_multiple_export_const_functions(self, ts_analyzer):
"""Test multiple export const arrow functions in same file."""
code = """export const notUndefined = <T>(val: T | undefined): val is T => Boolean(val);
export const uniqueBy = <T extends { [key: string]: unknown }>(array: T[], keys: (keyof T)[]) => {
return array.filter(
(item, index, self) => index === self.findIndex((t) => keys.every((key) => t[key] === item[key]))
);
};"""
functions = ts_analyzer.find_functions(code)
# Find the top-level exported functions
names = {f.name for f in functions if f.parent_function is None}
assert "notUndefined" in names
assert "uniqueBy" in names
def test_export_const_arrow_with_implicit_return(self, ts_analyzer):
"""Test export const arrow function with implicit return."""
code = """export const double = (n: number) => n * 2;"""
functions = ts_analyzer.find_functions(code)
assert len(functions) == 1
assert functions[0].name == "double"
assert functions[0].is_arrow is True
assert ts_analyzer.has_return_statement(functions[0], code) is True
def test_export_const_async_arrow_function(self, ts_analyzer):
"""Test export const async arrow function."""
code = """export const fetchData = async (url: string) => {
const response = await fetch(url);
return response.json();
};"""
functions = ts_analyzer.find_functions(code)
assert len(functions) == 1
assert functions[0].name == "fetchData"
assert functions[0].is_arrow is True
assert functions[0].is_async is True
assert ts_analyzer.has_return_statement(functions[0], code) is True
def test_non_exported_const_not_exported(self, ts_analyzer):
"""Test that non-exported const functions are not marked as exported."""
code = """const privateFunc = (x: number) => {
return x * 2;
};
export const publicFunc = (x: number) => {
return privateFunc(x);
};"""
# privateFunc should not be exported
is_private_exported, _ = ts_analyzer.is_function_exported(code, "privateFunc")
assert is_private_exported is False
# publicFunc should be exported
is_public_exported, name = ts_analyzer.is_function_exported(code, "publicFunc")
assert is_public_exported is True
assert name == "publicFunc"