mirror of
https://github.com/codeflash-ai/codeflash.git
synced 2026-05-04 18:25:17 +00:00
add e2e test for CI
This commit is contained in:
parent
7b7cc99f3a
commit
54ef71090e
51 changed files with 2813 additions and 9 deletions
|
|
@ -30,6 +30,29 @@ describe('bubbleSort', () => {
|
|||
bubbleSort(original);
|
||||
expect(original).toEqual([3, 1, 2]);
|
||||
});
|
||||
|
||||
test('sorts a larger reverse sorted array for performance', () => {
|
||||
const input = [];
|
||||
for (let i = 500; i >= 0; i--) {
|
||||
input.push(i);
|
||||
}
|
||||
const result = bubbleSort(input);
|
||||
expect(result[0]).toBe(0);
|
||||
expect(result[result.length - 1]).toBe(500);
|
||||
});
|
||||
|
||||
test('sorts a larger random array for performance', () => {
|
||||
const input = [
|
||||
42, 17, 93, 8, 67, 31, 55, 22, 89, 4,
|
||||
76, 12, 39, 58, 95, 26, 71, 48, 83, 19,
|
||||
64, 3, 88, 37, 52, 11, 79, 46, 91, 28,
|
||||
63, 7, 84, 33, 57, 14, 72, 41, 96, 24,
|
||||
69, 6, 81, 36, 54, 16, 77, 44, 90, 29
|
||||
];
|
||||
const result = bubbleSort(input);
|
||||
expect(result[0]).toBe(3);
|
||||
expect(result[result.length - 1]).toBe(96);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bubbleSortDescending', () => {
|
||||
|
|
@ -26,6 +26,20 @@ describe('reverseString', () => {
|
|||
test('handles spaces', () => {
|
||||
expect(reverseString('hello world')).toBe('dlrow olleh');
|
||||
});
|
||||
|
||||
test('reverses a longer string for performance', () => {
|
||||
const input = 'abcdefghijklmnopqrstuvwxyz'.repeat(20);
|
||||
const result = reverseString(input);
|
||||
expect(result.length).toBe(input.length);
|
||||
expect(result[0]).toBe('z');
|
||||
expect(result[result.length - 1]).toBe('a');
|
||||
});
|
||||
|
||||
test('reverses a medium string', () => {
|
||||
const input = 'The quick brown fox jumps over the lazy dog';
|
||||
const expected = 'god yzal eht revo spmuj xof nworb kciuq ehT';
|
||||
expect(reverseString(input)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isPalindrome', () => {
|
||||
64
code_to_optimize/js/code_to_optimize_js_esm/async_utils.js
Normal file
64
code_to_optimize/js/code_to_optimize_js_esm/async_utils.js
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* Async utility functions - ES Module version.
|
||||
* Contains intentionally inefficient implementations for optimization testing.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simulate a delay (for testing purposes).
|
||||
* @param {number} ms - Milliseconds to delay
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export function delay(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process items sequentially when they could be parallel.
|
||||
* Intentionally inefficient - processes items one at a time.
|
||||
* @param {any[]} items - Items to process
|
||||
* @param {function} processor - Async function to process each item
|
||||
* @returns {Promise<any[]>} Processed results
|
||||
*/
|
||||
export async function processItemsSequential(items, processor) {
|
||||
const results = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const result = await processor(items[i]);
|
||||
results.push(result);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map over items asynchronously with a concurrency limit.
|
||||
* Intentionally simple/inefficient implementation - ignores concurrency.
|
||||
* @param {any[]} items - Items to process
|
||||
* @param {function} mapper - Async mapper function
|
||||
* @param {number} concurrency - Max concurrent operations (currently ignored)
|
||||
* @returns {Promise<any[]>} Mapped results
|
||||
*/
|
||||
export async function asyncMap(items, mapper, concurrency = 1) {
|
||||
// Inefficient: ignores concurrency, processes sequentially
|
||||
const results = [];
|
||||
for (const item of items) {
|
||||
results.push(await mapper(item));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter items asynchronously.
|
||||
* Inefficient implementation that processes items one by one.
|
||||
* @param {any[]} items - Items to filter
|
||||
* @param {function} predicate - Async predicate function
|
||||
* @returns {Promise<any[]>} Filtered items
|
||||
*/
|
||||
export async function asyncFilter(items, predicate) {
|
||||
const results = [];
|
||||
for (const item of items) {
|
||||
const shouldInclude = await predicate(item);
|
||||
if (shouldInclude) {
|
||||
results.push(item);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
|
@ -8,10 +8,38 @@
|
|||
"name": "code-to-optimize-js-esm",
|
||||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.2",
|
||||
"codeflash": "file:../packages/codeflash",
|
||||
"eslint": "^9.39.2",
|
||||
"globals": "^17.1.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-junit": "^16.0.0"
|
||||
}
|
||||
},
|
||||
"../packages/codeflash": {
|
||||
"version": "0.1.0",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"better-sqlite3": "^9.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"codeflash": "bin/codeflash.js",
|
||||
"codeflash-setup": "bin/codeflash-setup.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"jest": ">=27.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"jest": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz",
|
||||
|
|
@ -508,6 +536,235 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
"version": "4.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
|
||||
"integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
|
||||
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/regexpp": {
|
||||
"version": "4.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
|
||||
"integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-array": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
|
||||
"integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/object-schema": "^2.1.7",
|
||||
"debug": "^4.3.1",
|
||||
"minimatch": "^3.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-helpers": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
|
||||
"integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/core": "^0.17.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/core": {
|
||||
"version": "0.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
|
||||
"integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz",
|
||||
"integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
"espree": "^10.0.1",
|
||||
"globals": "^14.0.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"js-yaml": "^4.1.1",
|
||||
"minimatch": "^3.1.2",
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true,
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/globals": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
||||
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/js-yaml": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "9.39.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz",
|
||||
"integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://eslint.org/donate"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/object-schema": {
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
|
||||
"integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/plugin-kit": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
|
||||
"integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/core": "^0.17.0",
|
||||
"levn": "^0.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanfs/core": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||
"integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=18.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanfs/node": {
|
||||
"version": "0.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
|
||||
"integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@humanfs/core": "^0.19.1",
|
||||
"@humanwhocodes/retry": "^0.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/module-importer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
|
||||
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=12.22"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/nzakas"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/retry": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
|
||||
"integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=18.18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/nzakas"
|
||||
}
|
||||
},
|
||||
"node_modules/@istanbuljs/load-nyc-config": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
|
||||
|
|
@ -949,6 +1206,13 @@
|
|||
"@babel/types": "^7.28.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/graceful-fs": {
|
||||
"version": "4.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
|
||||
|
|
@ -986,6 +1250,13 @@
|
|||
"@types/istanbul-lib-report": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "25.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.10.tgz",
|
||||
|
|
@ -1020,6 +1291,46 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-jsx": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
|
||||
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-escapes": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
|
||||
|
|
@ -1411,6 +1722,10 @@
|
|||
"node": ">= 0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/codeflash": {
|
||||
"resolved": "../packages/codeflash",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/collect-v8-coverage": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz",
|
||||
|
|
@ -1522,6 +1837,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/deep-is": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/deepmerge": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||
|
|
@ -1609,6 +1931,176 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "9.39.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz",
|
||||
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
"@eslint/config-array": "^0.21.1",
|
||||
"@eslint/config-helpers": "^0.4.2",
|
||||
"@eslint/core": "^0.17.0",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "9.39.2",
|
||||
"@eslint/plugin-kit": "^0.4.1",
|
||||
"@humanfs/node": "^0.16.6",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@humanwhocodes/retry": "^0.4.2",
|
||||
"@types/estree": "^1.0.6",
|
||||
"ajv": "^6.12.4",
|
||||
"chalk": "^4.0.0",
|
||||
"cross-spawn": "^7.0.6",
|
||||
"debug": "^4.3.2",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"eslint-scope": "^8.4.0",
|
||||
"eslint-visitor-keys": "^4.2.1",
|
||||
"espree": "^10.4.0",
|
||||
"esquery": "^1.5.0",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"file-entry-cache": "^8.0.0",
|
||||
"find-up": "^5.0.0",
|
||||
"glob-parent": "^6.0.2",
|
||||
"ignore": "^5.2.0",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"is-glob": "^4.0.0",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"minimatch": "^3.1.2",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.3"
|
||||
},
|
||||
"bin": {
|
||||
"eslint": "bin/eslint.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://eslint.org/donate"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"jiti": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"jiti": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-scope": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
|
||||
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^5.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-visitor-keys": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/find-up": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"locate-path": "^6.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"p-locate": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/p-locate": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
|
||||
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"p-limit": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/espree": {
|
||||
"version": "10.4.0",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
|
||||
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"acorn": "^8.15.0",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
|
|
@ -1623,6 +2115,52 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/esquery": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
|
||||
"integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"estraverse": "^5.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/esrecurse": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
|
||||
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"estraverse": "^5.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/estraverse": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
|
||||
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/execa": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
|
||||
|
|
@ -1673,6 +2211,13 @@
|
|||
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
|
|
@ -1680,6 +2225,13 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-levenshtein": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
||||
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fb-watchman": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
|
||||
|
|
@ -1690,6 +2242,19 @@
|
|||
"bser": "2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/file-entry-cache": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
|
||||
"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"flat-cache": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
|
|
@ -1717,6 +2282,27 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/flat-cache": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
|
||||
"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"flatted": "^3.2.9",
|
||||
"keyv": "^4.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/flatted": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
|
||||
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
|
|
@ -1814,6 +2400,32 @@
|
|||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "17.2.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-17.2.0.tgz",
|
||||
"integrity": "sha512-tovnCz/fEq+Ripoq+p/gN1u7l6A7wwkoBT9pRCzTHzsD/LvADIzXZdjmRymh5Ztf0DYC3Rwg5cZRYjxzBmzbWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
|
|
@ -1861,6 +2473,43 @@
|
|||
"node": ">=10.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
|
||||
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"parent-module": "^1.0.0",
|
||||
"resolve-from": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/import-fresh/node_modules/resolve-from": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/import-local": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz",
|
||||
|
|
@ -1933,6 +2582,16 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
|
|
@ -1953,6 +2612,19 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
|
|
@ -2713,6 +3385,13 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/json-buffer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json-parse-even-better-errors": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||
|
|
@ -2720,6 +3399,20 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json-stable-stringify-without-jsonify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
|
||||
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json5": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||
|
|
@ -2733,6 +3426,16 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"json-buffer": "3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
|
|
@ -2753,6 +3456,20 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/levn": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||
"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prelude-ls": "^1.2.1",
|
||||
"type-check": "~0.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
|
|
@ -2773,6 +3490,13 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||
|
|
@ -2956,6 +3680,24 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||
"integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"deep-is": "^0.1.3",
|
||||
"fast-levenshtein": "^2.0.6",
|
||||
"levn": "^0.4.1",
|
||||
"prelude-ls": "^1.2.1",
|
||||
"type-check": "^0.4.0",
|
||||
"word-wrap": "^1.2.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/p-limit": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||
|
|
@ -3011,6 +3753,19 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"callsites": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-json": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
|
||||
|
|
@ -3110,6 +3865,16 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format": {
|
||||
"version": "29.7.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
|
||||
|
|
@ -3152,6 +3917,16 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/pure-rand": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
|
||||
|
|
@ -3474,6 +4249,19 @@
|
|||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prelude-ls": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-detect": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
||||
|
|
@ -3535,6 +4323,16 @@
|
|||
"browserslist": ">= 4.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
|
|
@ -3586,6 +4384,16 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/word-wrap": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
||||
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
|
|
@ -10,16 +10,14 @@
|
|||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.2",
|
||||
"codeflash": "file:../packages/codeflash",
|
||||
"jest": "^29.7.0",
|
||||
"globals": "^17.1.0",
|
||||
"eslint": "^9.39.2",
|
||||
"globals": "^17.1.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-junit": "^16.0.0"
|
||||
},
|
||||
"codeflash": {
|
||||
"moduleRoot": ".",
|
||||
"formatterCmds": [
|
||||
"npx eslint --fix $file"
|
||||
],
|
||||
"language": "javascript"
|
||||
"testsRoot": "tests",
|
||||
"disableTelemetry": true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* Tests for async utility functions - ES Module
|
||||
*/
|
||||
import { delay, processItemsSequential, asyncMap, asyncFilter } from '../async_utils.js';
|
||||
|
||||
describe('processItemsSequential', () => {
|
||||
test('processes all items', async () => {
|
||||
const items = [1, 2, 3, 4, 5];
|
||||
const processor = async (x) => x * 2;
|
||||
const results = await processItemsSequential(items, processor);
|
||||
expect(results).toEqual([2, 4, 6, 8, 10]);
|
||||
});
|
||||
|
||||
test('handles empty array', async () => {
|
||||
const results = await processItemsSequential([], async (x) => x);
|
||||
expect(results).toEqual([]);
|
||||
});
|
||||
|
||||
test('handles async operations with delays', async () => {
|
||||
const items = [1, 2, 3];
|
||||
const processor = async (x) => {
|
||||
await delay(1);
|
||||
return x + 10;
|
||||
};
|
||||
const results = await processItemsSequential(items, processor);
|
||||
expect(results).toEqual([11, 12, 13]);
|
||||
});
|
||||
|
||||
test('preserves order', async () => {
|
||||
const items = [5, 4, 3, 2, 1];
|
||||
const processor = async (x) => x.toString();
|
||||
const results = await processItemsSequential(items, processor);
|
||||
expect(results).toEqual(['5', '4', '3', '2', '1']);
|
||||
});
|
||||
|
||||
test('handles larger arrays', async () => {
|
||||
const items = Array.from({ length: 20 }, (_, i) => i);
|
||||
const processor = async (x) => x * 2;
|
||||
const results = await processItemsSequential(items, processor);
|
||||
expect(results.length).toBe(20);
|
||||
expect(results[0]).toBe(0);
|
||||
expect(results[19]).toBe(38);
|
||||
});
|
||||
});
|
||||
|
||||
describe('asyncMap', () => {
|
||||
test('maps all items', async () => {
|
||||
const items = [1, 2, 3];
|
||||
const mapper = async (x) => x * 10;
|
||||
const results = await asyncMap(items, mapper);
|
||||
expect(results).toEqual([10, 20, 30]);
|
||||
});
|
||||
|
||||
test('handles empty array', async () => {
|
||||
const results = await asyncMap([], async (x) => x);
|
||||
expect(results).toEqual([]);
|
||||
});
|
||||
|
||||
test('handles objects', async () => {
|
||||
const items = [{ a: 1 }, { a: 2 }];
|
||||
const mapper = async (obj) => ({ ...obj, b: obj.a * 2 });
|
||||
const results = await asyncMap(items, mapper);
|
||||
expect(results).toEqual([{ a: 1, b: 2 }, { a: 2, b: 4 }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('asyncFilter', () => {
|
||||
test('filters items based on predicate', async () => {
|
||||
const items = [1, 2, 3, 4, 5, 6];
|
||||
const predicate = async (x) => x % 2 === 0;
|
||||
const results = await asyncFilter(items, predicate);
|
||||
expect(results).toEqual([2, 4, 6]);
|
||||
});
|
||||
|
||||
test('handles empty array', async () => {
|
||||
const results = await asyncFilter([], async () => true);
|
||||
expect(results).toEqual([]);
|
||||
});
|
||||
|
||||
test('handles all items filtered out', async () => {
|
||||
const items = [1, 2, 3];
|
||||
const results = await asyncFilter(items, async () => false);
|
||||
expect(results).toEqual([]);
|
||||
});
|
||||
});
|
||||
88
code_to_optimize/js/code_to_optimize_ts/data_processor.ts
Normal file
88
code_to_optimize/js/code_to_optimize_ts/data_processor.ts
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
* DataProcessor class - demonstrates class method optimization in TypeScript.
|
||||
* Contains intentionally inefficient implementations for optimization testing.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A class for processing data arrays with various operations.
|
||||
*/
|
||||
export class DataProcessor<T> {
|
||||
private data: T[];
|
||||
|
||||
/**
|
||||
* Create a DataProcessor instance.
|
||||
* @param data - Initial data array
|
||||
*/
|
||||
constructor(data: T[] = []) {
|
||||
this.data = [...data];
|
||||
}
|
||||
|
||||
/**
|
||||
* Find duplicates in the data array.
|
||||
* Intentionally inefficient O(n²) implementation.
|
||||
* @returns Array of duplicate values
|
||||
*/
|
||||
findDuplicates(): T[] {
|
||||
const duplicates: T[] = [];
|
||||
for (let i = 0; i < this.data.length; i++) {
|
||||
for (let j = i + 1; j < this.data.length; j++) {
|
||||
if (this.data[i] === this.data[j]) {
|
||||
if (!duplicates.includes(this.data[i])) {
|
||||
duplicates.push(this.data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return duplicates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the data using bubble sort.
|
||||
* Intentionally inefficient O(n²) implementation.
|
||||
* @returns Sorted copy of the data
|
||||
*/
|
||||
sortData(): T[] {
|
||||
const result = [...this.data];
|
||||
const n = result.length;
|
||||
for (let i = 0; i < n; i++) {
|
||||
for (let j = 0; j < n - 1; j++) {
|
||||
if (result[j] > result[j + 1]) {
|
||||
const temp = result[j];
|
||||
result[j] = result[j + 1];
|
||||
result[j + 1] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unique values from the data.
|
||||
* Intentionally inefficient O(n²) implementation.
|
||||
* @returns Array of unique values
|
||||
*/
|
||||
getUnique(): T[] {
|
||||
const unique: T[] = [];
|
||||
for (let i = 0; i < this.data.length; i++) {
|
||||
let found = false;
|
||||
for (let j = 0; j < unique.length; j++) {
|
||||
if (unique[j] === this.data[i]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
unique.push(this.data[i]);
|
||||
}
|
||||
}
|
||||
return unique;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data array.
|
||||
* @returns The data array
|
||||
*/
|
||||
getData(): T[] {
|
||||
return [...this.data];
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,10 @@
|
|||
"test:coverage": "jest --coverage",
|
||||
"build": "tsc"
|
||||
},
|
||||
"codeflash": {
|
||||
"moduleRoot": ".",
|
||||
"testsRoot": "tests"
|
||||
},
|
||||
"keywords": [
|
||||
"codeflash",
|
||||
"optimization",
|
||||
|
|
@ -4,14 +4,21 @@
|
|||
|
||||
/**
|
||||
* Reverse a string character by character.
|
||||
* This is intentionally inefficient - uses string concatenation in a loop.
|
||||
* This is intentionally inefficient O(n²) - rebuilds result string each iteration.
|
||||
* @param str - The string to reverse
|
||||
* @returns The reversed string
|
||||
*/
|
||||
export function reverseString(str: string): string {
|
||||
// Intentionally inefficient O(n²) implementation for testing
|
||||
let result = '';
|
||||
for (let i = str.length - 1; i >= 0; i--) {
|
||||
result += str[i];
|
||||
// Rebuild the entire result string each iteration (very inefficient)
|
||||
let temp = '';
|
||||
for (let j = 0; j < result.length; j++) {
|
||||
temp += result[j];
|
||||
}
|
||||
temp += str[i];
|
||||
result = temp;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -34,6 +34,29 @@ describe('bubbleSort', () => {
|
|||
bubbleSort(original);
|
||||
expect(original).toEqual([3, 1, 2]);
|
||||
});
|
||||
|
||||
test('sorts a larger reverse sorted array for performance', () => {
|
||||
const input: number[] = [];
|
||||
for (let i = 500; i >= 0; i--) {
|
||||
input.push(i);
|
||||
}
|
||||
const result = bubbleSort(input);
|
||||
expect(result[0]).toBe(0);
|
||||
expect(result[result.length - 1]).toBe(500);
|
||||
});
|
||||
|
||||
test('sorts a larger random array for performance', () => {
|
||||
const input = [
|
||||
42, 17, 93, 8, 67, 31, 55, 22, 89, 4,
|
||||
76, 12, 39, 58, 95, 26, 71, 48, 83, 19,
|
||||
64, 3, 88, 37, 52, 11, 79, 46, 91, 28,
|
||||
63, 7, 84, 33, 57, 14, 72, 41, 96, 24,
|
||||
69, 6, 81, 36, 54, 16, 77, 44, 90, 29
|
||||
];
|
||||
const result = bubbleSort(input);
|
||||
expect(result[0]).toBe(3);
|
||||
expect(result[result.length - 1]).toBe(96);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bubbleSortDescending', () => {
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
import { DataProcessor } from '../data_processor';
|
||||
|
||||
describe('DataProcessor', () => {
|
||||
describe('findDuplicates', () => {
|
||||
test('finds duplicates in array with repeated values', () => {
|
||||
const processor = new DataProcessor([1, 2, 3, 2, 4, 3, 5]);
|
||||
expect(processor.findDuplicates().sort()).toEqual([2, 3]);
|
||||
});
|
||||
|
||||
test('returns empty array when no duplicates', () => {
|
||||
const processor = new DataProcessor([1, 2, 3, 4, 5]);
|
||||
expect(processor.findDuplicates()).toEqual([]);
|
||||
});
|
||||
|
||||
test('handles empty array', () => {
|
||||
const processor = new DataProcessor<number>([]);
|
||||
expect(processor.findDuplicates()).toEqual([]);
|
||||
});
|
||||
|
||||
test('handles array with all same values', () => {
|
||||
const processor = new DataProcessor([5, 5, 5, 5]);
|
||||
expect(processor.findDuplicates()).toEqual([5]);
|
||||
});
|
||||
|
||||
test('handles larger arrays with duplicates', () => {
|
||||
const data: number[] = [];
|
||||
for (let i = 0; i < 100; i++) {
|
||||
data.push(i % 20);
|
||||
}
|
||||
const processor = new DataProcessor(data);
|
||||
const duplicates = processor.findDuplicates();
|
||||
expect(duplicates.length).toBe(20);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sortData', () => {
|
||||
test('sorts numbers in ascending order', () => {
|
||||
const processor = new DataProcessor([5, 2, 8, 1, 9]);
|
||||
expect(processor.sortData()).toEqual([1, 2, 5, 8, 9]);
|
||||
});
|
||||
|
||||
test('handles already sorted array', () => {
|
||||
const processor = new DataProcessor([1, 2, 3, 4, 5]);
|
||||
expect(processor.sortData()).toEqual([1, 2, 3, 4, 5]);
|
||||
});
|
||||
|
||||
test('handles reverse sorted array', () => {
|
||||
const processor = new DataProcessor([5, 4, 3, 2, 1]);
|
||||
expect(processor.sortData()).toEqual([1, 2, 3, 4, 5]);
|
||||
});
|
||||
|
||||
test('handles array with duplicates', () => {
|
||||
const processor = new DataProcessor([3, 1, 4, 1, 5, 9, 2, 6, 5]);
|
||||
expect(processor.sortData()).toEqual([1, 1, 2, 3, 4, 5, 5, 6, 9]);
|
||||
});
|
||||
|
||||
test('handles larger arrays', () => {
|
||||
const data: number[] = [];
|
||||
for (let i = 500; i >= 0; i--) {
|
||||
data.push(i);
|
||||
}
|
||||
const processor = new DataProcessor(data);
|
||||
const sorted = processor.sortData();
|
||||
expect(sorted[0]).toBe(0);
|
||||
expect(sorted[sorted.length - 1]).toBe(500);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUnique', () => {
|
||||
test('returns unique values', () => {
|
||||
const processor = new DataProcessor([1, 2, 2, 3, 3, 3, 4]);
|
||||
expect(processor.getUnique()).toEqual([1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
test('preserves order of first occurrence', () => {
|
||||
const processor = new DataProcessor([3, 1, 2, 1, 3, 2]);
|
||||
expect(processor.getUnique()).toEqual([3, 1, 2]);
|
||||
});
|
||||
|
||||
test('handles empty array', () => {
|
||||
const processor = new DataProcessor<number>([]);
|
||||
expect(processor.getUnique()).toEqual([]);
|
||||
});
|
||||
|
||||
test('handles array with all unique values', () => {
|
||||
const processor = new DataProcessor([1, 2, 3, 4, 5]);
|
||||
expect(processor.getUnique()).toEqual([1, 2, 3, 4, 5]);
|
||||
});
|
||||
|
||||
test('handles strings', () => {
|
||||
const processor = new DataProcessor(['a', 'b', 'a', 'c', 'b']);
|
||||
expect(processor.getUnique()).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -20,6 +20,20 @@ describe('reverseString', () => {
|
|||
test('handles special characters', () => {
|
||||
expect(reverseString('a!b@c#')).toBe('#c@b!a');
|
||||
});
|
||||
|
||||
test('reverses a longer string for performance', () => {
|
||||
const input = 'abcdefghijklmnopqrstuvwxyz'.repeat(20);
|
||||
const result = reverseString(input);
|
||||
expect(result.length).toBe(input.length);
|
||||
expect(result[0]).toBe('z');
|
||||
expect(result[result.length - 1]).toBe('a');
|
||||
});
|
||||
|
||||
test('reverses a medium string', () => {
|
||||
const input = 'The quick brown fox jumps over the lazy dog';
|
||||
const expected = 'god yzal eht revo spmuj xof nworb kciuq ehT';
|
||||
expect(reverseString(input)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isPalindrome', () => {
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
# These version placeholders will be replaced by uv-dynamic-versioning during build.
|
||||
__version__ = "0.20.0"
|
||||
__version__ = "0.20.0.post91.dev0+28f8eb18"
|
||||
|
|
|
|||
862
tests/code_utils/test_config_js.py
Normal file
862
tests/code_utils/test_config_js.py
Normal file
|
|
@ -0,0 +1,862 @@
|
|||
"""Tests for JavaScript/TypeScript configuration detection and parsing."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from codeflash.code_utils.config_js import (
|
||||
PACKAGE_JSON_CACHE,
|
||||
PACKAGE_JSON_DATA_CACHE,
|
||||
clear_cache,
|
||||
detect_formatter,
|
||||
detect_language,
|
||||
detect_module_root,
|
||||
detect_test_runner,
|
||||
find_package_json,
|
||||
get_package_json_data,
|
||||
parse_package_json_config,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def clear_caches() -> None:
|
||||
"""Clear all caches before each test."""
|
||||
clear_cache()
|
||||
|
||||
|
||||
class TestGetPackageJsonData:
|
||||
"""Tests for get_package_json_data function."""
|
||||
|
||||
def test_loads_valid_package_json(self, tmp_path: Path) -> None:
|
||||
"""Should load and return valid package.json data."""
|
||||
package_json = tmp_path / "package.json"
|
||||
data = {"name": "test-project", "version": "1.0.0"}
|
||||
package_json.write_text(json.dumps(data))
|
||||
|
||||
result = get_package_json_data(package_json)
|
||||
|
||||
assert result == data
|
||||
|
||||
def test_caches_loaded_data(self, tmp_path: Path) -> None:
|
||||
"""Should cache package.json data after first load."""
|
||||
package_json = tmp_path / "package.json"
|
||||
data = {"name": "test-project"}
|
||||
package_json.write_text(json.dumps(data))
|
||||
|
||||
# First call
|
||||
result1 = get_package_json_data(package_json)
|
||||
# Modify file
|
||||
package_json.write_text(json.dumps({"name": "modified"}))
|
||||
# Second call should return cached data
|
||||
result2 = get_package_json_data(package_json)
|
||||
|
||||
assert result1 == result2 == data
|
||||
|
||||
def test_returns_none_for_invalid_json(self, tmp_path: Path) -> None:
|
||||
"""Should return None for invalid JSON."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text("{ invalid json }")
|
||||
|
||||
result = get_package_json_data(package_json)
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_returns_none_for_nonexistent_file(self, tmp_path: Path) -> None:
|
||||
"""Should return None for non-existent file."""
|
||||
package_json = tmp_path / "package.json"
|
||||
|
||||
result = get_package_json_data(package_json)
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_returns_none_for_unreadable_file(self, tmp_path: Path) -> None:
|
||||
"""Should return None if file cannot be read."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text("{}")
|
||||
package_json.chmod(0o000)
|
||||
|
||||
try:
|
||||
result = get_package_json_data(package_json)
|
||||
assert result is None
|
||||
finally:
|
||||
package_json.chmod(0o644)
|
||||
|
||||
|
||||
class TestDetectLanguage:
|
||||
"""Tests for detect_language function."""
|
||||
|
||||
def test_detects_typescript_with_tsconfig(self, tmp_path: Path) -> None:
|
||||
"""Should detect TypeScript when tsconfig.json exists."""
|
||||
(tmp_path / "tsconfig.json").write_text("{}")
|
||||
|
||||
result = detect_language(tmp_path)
|
||||
|
||||
assert result == "typescript"
|
||||
|
||||
def test_detects_javascript_without_tsconfig(self, tmp_path: Path) -> None:
|
||||
"""Should detect JavaScript when no tsconfig.json exists."""
|
||||
result = detect_language(tmp_path)
|
||||
|
||||
assert result == "javascript"
|
||||
|
||||
def test_detects_typescript_with_complex_tsconfig(self, tmp_path: Path) -> None:
|
||||
"""Should detect TypeScript even with complex tsconfig."""
|
||||
tsconfig = {
|
||||
"compilerOptions": {"target": "ES2020", "module": "commonjs"},
|
||||
"include": ["src/**/*"],
|
||||
}
|
||||
(tmp_path / "tsconfig.json").write_text(json.dumps(tsconfig))
|
||||
|
||||
result = detect_language(tmp_path)
|
||||
|
||||
assert result == "typescript"
|
||||
|
||||
|
||||
class TestDetectModuleRoot:
|
||||
"""Tests for detect_module_root function."""
|
||||
|
||||
def test_detects_from_exports_string(self, tmp_path: Path) -> None:
|
||||
"""Should detect module root from exports string field."""
|
||||
(tmp_path / "lib").mkdir()
|
||||
package_data = {"exports": "./lib/index.js"}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "lib"
|
||||
|
||||
def test_detects_from_exports_object_dot(self, tmp_path: Path) -> None:
|
||||
"""Should detect module root from exports object with '.' key."""
|
||||
(tmp_path / "dist").mkdir()
|
||||
package_data = {"exports": {".": "./dist/index.js"}}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "dist"
|
||||
|
||||
def test_detects_from_exports_object_nested(self, tmp_path: Path) -> None:
|
||||
"""Should detect module root from nested exports object."""
|
||||
(tmp_path / "src").mkdir()
|
||||
package_data = {"exports": {".": {"import": "./src/index.mjs", "require": "./src/index.cjs"}}}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "src"
|
||||
|
||||
def test_detects_from_exports_import_key(self, tmp_path: Path) -> None:
|
||||
"""Should detect from exports with direct import key."""
|
||||
(tmp_path / "esm").mkdir()
|
||||
package_data = {"exports": {"import": "./esm/index.js"}}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "esm"
|
||||
|
||||
def test_detects_from_module_field(self, tmp_path: Path) -> None:
|
||||
"""Should detect module root from module field (ESM entry)."""
|
||||
(tmp_path / "es").mkdir()
|
||||
package_data = {"module": "./es/index.js"}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "es"
|
||||
|
||||
def test_detects_from_main_field(self, tmp_path: Path) -> None:
|
||||
"""Should detect module root from main field (CJS entry)."""
|
||||
(tmp_path / "lib").mkdir()
|
||||
package_data = {"main": "./lib/index.js"}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "lib"
|
||||
|
||||
def test_prefers_exports_over_module(self, tmp_path: Path) -> None:
|
||||
"""Should prefer exports field over module field."""
|
||||
(tmp_path / "exports-dir").mkdir()
|
||||
(tmp_path / "module-dir").mkdir()
|
||||
package_data = {"exports": "./exports-dir/index.js", "module": "./module-dir/index.js"}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "exports-dir"
|
||||
|
||||
def test_prefers_module_over_main(self, tmp_path: Path) -> None:
|
||||
"""Should prefer module field over main field."""
|
||||
(tmp_path / "esm").mkdir()
|
||||
(tmp_path / "cjs").mkdir()
|
||||
package_data = {"module": "./esm/index.js", "main": "./cjs/index.js"}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "esm"
|
||||
|
||||
def test_detects_src_directory_convention(self, tmp_path: Path) -> None:
|
||||
"""Should detect src/ directory when no package.json fields point elsewhere."""
|
||||
(tmp_path / "src").mkdir()
|
||||
package_data = {}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "src"
|
||||
|
||||
def test_falls_back_to_current_directory(self, tmp_path: Path) -> None:
|
||||
"""Should fall back to '.' when nothing else matches."""
|
||||
package_data = {}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "."
|
||||
|
||||
def test_ignores_nonexistent_directory_from_exports(self, tmp_path: Path) -> None:
|
||||
"""Should ignore exports pointing to non-existent directory."""
|
||||
(tmp_path / "src").mkdir()
|
||||
package_data = {"exports": "./nonexistent/index.js"}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "src"
|
||||
|
||||
def test_ignores_root_level_main(self, tmp_path: Path) -> None:
|
||||
"""Should ignore main that points to root level file."""
|
||||
(tmp_path / "src").mkdir()
|
||||
package_data = {"main": "./index.js"}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "src"
|
||||
|
||||
def test_handles_deeply_nested_exports(self, tmp_path: Path) -> None:
|
||||
"""Should handle deeply nested export paths."""
|
||||
(tmp_path / "packages" / "core" / "dist").mkdir(parents=True)
|
||||
package_data = {"exports": {".": {"import": "./packages/core/dist/index.mjs"}}}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "packages/core/dist"
|
||||
|
||||
def test_handles_empty_exports(self, tmp_path: Path) -> None:
|
||||
"""Should handle empty exports gracefully."""
|
||||
(tmp_path / "src").mkdir()
|
||||
package_data = {"exports": {}}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "src"
|
||||
|
||||
def test_handles_null_exports(self, tmp_path: Path) -> None:
|
||||
"""Should handle null/None exports gracefully."""
|
||||
package_data = {"exports": None}
|
||||
|
||||
result = detect_module_root(tmp_path, package_data)
|
||||
|
||||
assert result == "."
|
||||
|
||||
|
||||
class TestDetectTestRunner:
|
||||
"""Tests for detect_test_runner function."""
|
||||
|
||||
def test_detects_vitest_from_dev_dependencies(self, tmp_path: Path) -> None:
|
||||
"""Should detect vitest from devDependencies."""
|
||||
package_data = {"devDependencies": {"vitest": "^1.0.0"}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "vitest"
|
||||
|
||||
def test_detects_jest_from_dev_dependencies(self, tmp_path: Path) -> None:
|
||||
"""Should detect jest from devDependencies."""
|
||||
package_data = {"devDependencies": {"jest": "^29.0.0"}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "jest"
|
||||
|
||||
def test_detects_mocha_from_dev_dependencies(self, tmp_path: Path) -> None:
|
||||
"""Should detect mocha from devDependencies."""
|
||||
package_data = {"devDependencies": {"mocha": "^10.0.0"}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "mocha"
|
||||
|
||||
def test_detects_from_dependencies(self, tmp_path: Path) -> None:
|
||||
"""Should also check dependencies (not just devDependencies)."""
|
||||
package_data = {"dependencies": {"jest": "^29.0.0"}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "jest"
|
||||
|
||||
def test_prefers_vitest_over_jest(self, tmp_path: Path) -> None:
|
||||
"""Should prefer vitest when both are present."""
|
||||
package_data = {"devDependencies": {"vitest": "^1.0.0", "jest": "^29.0.0"}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "vitest"
|
||||
|
||||
def test_prefers_jest_over_mocha(self, tmp_path: Path) -> None:
|
||||
"""Should prefer jest over mocha."""
|
||||
package_data = {"devDependencies": {"jest": "^29.0.0", "mocha": "^10.0.0"}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "jest"
|
||||
|
||||
def test_detects_vitest_from_test_script(self, tmp_path: Path) -> None:
|
||||
"""Should detect vitest from scripts.test."""
|
||||
package_data = {"scripts": {"test": "vitest run"}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "vitest"
|
||||
|
||||
def test_detects_jest_from_test_script(self, tmp_path: Path) -> None:
|
||||
"""Should detect jest from scripts.test."""
|
||||
package_data = {"scripts": {"test": "jest --coverage"}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "jest"
|
||||
|
||||
def test_detects_mocha_from_test_script(self, tmp_path: Path) -> None:
|
||||
"""Should detect mocha from scripts.test."""
|
||||
package_data = {"scripts": {"test": "mocha tests/**/*.js"}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "mocha"
|
||||
|
||||
def test_detects_from_npx_command(self, tmp_path: Path) -> None:
|
||||
"""Should detect runner from npx command in test script."""
|
||||
package_data = {"scripts": {"test": "npx jest"}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "jest"
|
||||
|
||||
def test_detects_case_insensitive(self, tmp_path: Path) -> None:
|
||||
"""Should detect runner case-insensitively from scripts."""
|
||||
package_data = {"scripts": {"test": "JEST --ci"}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "jest"
|
||||
|
||||
def test_prefers_deps_over_scripts(self, tmp_path: Path) -> None:
|
||||
"""Should prefer devDependencies detection over scripts."""
|
||||
package_data = {"devDependencies": {"vitest": "^1.0.0"}, "scripts": {"test": "jest"}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "vitest"
|
||||
|
||||
def test_defaults_to_jest(self, tmp_path: Path) -> None:
|
||||
"""Should default to jest when nothing is detected."""
|
||||
package_data = {}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "jest"
|
||||
|
||||
def test_handles_complex_test_script(self, tmp_path: Path) -> None:
|
||||
"""Should detect from complex test scripts."""
|
||||
package_data = {"scripts": {"test": "NODE_OPTIONS='--experimental-vm-modules' jest --coverage"}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "jest"
|
||||
|
||||
def test_handles_missing_scripts(self, tmp_path: Path) -> None:
|
||||
"""Should handle missing scripts gracefully."""
|
||||
package_data = {"name": "test"}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "jest"
|
||||
|
||||
def test_handles_non_string_test_script(self, tmp_path: Path) -> None:
|
||||
"""Should handle non-string test script gracefully."""
|
||||
package_data = {"scripts": {"test": 123}}
|
||||
|
||||
result = detect_test_runner(tmp_path, package_data)
|
||||
|
||||
assert result == "jest"
|
||||
|
||||
|
||||
class TestDetectFormatter:
|
||||
"""Tests for detect_formatter function."""
|
||||
|
||||
def test_detects_prettier_from_dev_dependencies(self, tmp_path: Path) -> None:
|
||||
"""Should detect prettier from devDependencies."""
|
||||
package_data = {"devDependencies": {"prettier": "^3.0.0"}}
|
||||
|
||||
result = detect_formatter(tmp_path, package_data)
|
||||
|
||||
assert result == ["npx prettier --write $file"]
|
||||
|
||||
def test_detects_eslint_from_dev_dependencies(self, tmp_path: Path) -> None:
|
||||
"""Should detect eslint from devDependencies."""
|
||||
package_data = {"devDependencies": {"eslint": "^8.0.0"}}
|
||||
|
||||
result = detect_formatter(tmp_path, package_data)
|
||||
|
||||
assert result == ["npx eslint --fix $file"]
|
||||
|
||||
def test_detects_from_dependencies(self, tmp_path: Path) -> None:
|
||||
"""Should also check dependencies."""
|
||||
package_data = {"dependencies": {"prettier": "^3.0.0"}}
|
||||
|
||||
result = detect_formatter(tmp_path, package_data)
|
||||
|
||||
assert result == ["npx prettier --write $file"]
|
||||
|
||||
def test_prefers_prettier_over_eslint(self, tmp_path: Path) -> None:
|
||||
"""Should prefer prettier when both are present."""
|
||||
package_data = {"devDependencies": {"prettier": "^3.0.0", "eslint": "^8.0.0"}}
|
||||
|
||||
result = detect_formatter(tmp_path, package_data)
|
||||
|
||||
assert result == ["npx prettier --write $file"]
|
||||
|
||||
def test_returns_none_when_no_formatter(self, tmp_path: Path) -> None:
|
||||
"""Should return None when no formatter is detected."""
|
||||
package_data = {"devDependencies": {"typescript": "^5.0.0"}}
|
||||
|
||||
result = detect_formatter(tmp_path, package_data)
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_returns_none_for_empty_deps(self, tmp_path: Path) -> None:
|
||||
"""Should return None for empty dependencies."""
|
||||
package_data = {}
|
||||
|
||||
result = detect_formatter(tmp_path, package_data)
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_detects_eslint_related_packages(self, tmp_path: Path) -> None:
|
||||
"""Should detect eslint even with scoped packages."""
|
||||
package_data = {"devDependencies": {"eslint": "^8.0.0", "@eslint/js": "^8.0.0"}}
|
||||
|
||||
result = detect_formatter(tmp_path, package_data)
|
||||
|
||||
assert result == ["npx eslint --fix $file"]
|
||||
|
||||
|
||||
class TestFindPackageJson:
|
||||
"""Tests for find_package_json function."""
|
||||
|
||||
def test_finds_explicit_package_json(self, tmp_path: Path) -> None:
|
||||
"""Should find explicitly provided package.json path."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text("{}")
|
||||
|
||||
result = find_package_json(package_json)
|
||||
|
||||
assert result == package_json
|
||||
|
||||
def test_returns_none_for_wrong_filename(self, tmp_path: Path) -> None:
|
||||
"""Should return None if explicit path is not package.json."""
|
||||
other_file = tmp_path / "other.json"
|
||||
other_file.write_text("{}")
|
||||
|
||||
result = find_package_json(other_file)
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_returns_none_for_nonexistent_explicit(self, tmp_path: Path) -> None:
|
||||
"""Should return None if explicit package.json doesn't exist."""
|
||||
package_json = tmp_path / "package.json"
|
||||
|
||||
result = find_package_json(package_json)
|
||||
|
||||
assert result is None
|
||||
|
||||
|
||||
class TestParsePackageJsonConfig:
|
||||
"""Tests for parse_package_json_config function."""
|
||||
|
||||
def test_parses_minimal_package_json(self, tmp_path: Path) -> None:
|
||||
"""Should parse package.json without codeflash section."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test", "devDependencies": {"jest": "^29.0.0"}}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, path = result
|
||||
assert config["language"] == "javascript"
|
||||
assert config["test_runner"] == "jest"
|
||||
assert config["pytest_cmd"] == "jest"
|
||||
assert path == package_json
|
||||
|
||||
def test_parses_typescript_project(self, tmp_path: Path) -> None:
|
||||
"""Should detect TypeScript project."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test"}))
|
||||
(tmp_path / "tsconfig.json").write_text("{}")
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["language"] == "typescript"
|
||||
|
||||
def test_auto_detects_module_root(self, tmp_path: Path) -> None:
|
||||
"""Should auto-detect module root from package.json."""
|
||||
(tmp_path / "src").mkdir()
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test", "main": "./src/index.js"}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["module_root"] == str((tmp_path / "src").resolve())
|
||||
|
||||
def test_respects_module_root_override(self, tmp_path: Path) -> None:
|
||||
"""Should respect moduleRoot override in codeflash config."""
|
||||
(tmp_path / "lib").mkdir()
|
||||
(tmp_path / "src").mkdir()
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(
|
||||
json.dumps({"name": "test", "main": "./src/index.js", "codeflash": {"moduleRoot": "lib"}})
|
||||
)
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["module_root"] == str((tmp_path / "lib").resolve())
|
||||
|
||||
def test_auto_detects_formatter(self, tmp_path: Path) -> None:
|
||||
"""Should auto-detect formatter from devDependencies."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test", "devDependencies": {"prettier": "^3.0.0"}}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["formatter_cmds"] == ["npx prettier --write $file"]
|
||||
|
||||
def test_respects_formatter_override(self, tmp_path: Path) -> None:
|
||||
"""Should respect formatterCmds override."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"name": "test",
|
||||
"devDependencies": {"prettier": "^3.0.0"},
|
||||
"codeflash": {"formatterCmds": ["custom-formatter $file"]},
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["formatter_cmds"] == ["custom-formatter $file"]
|
||||
|
||||
def test_parses_ignore_paths(self, tmp_path: Path) -> None:
|
||||
"""Should parse ignorePaths from codeflash config."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test", "codeflash": {"ignorePaths": ["dist", "node_modules"]}}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert str((tmp_path / "dist").resolve()) in config["ignore_paths"]
|
||||
assert str((tmp_path / "node_modules").resolve()) in config["ignore_paths"]
|
||||
|
||||
def test_parses_benchmarks_root(self, tmp_path: Path) -> None:
|
||||
"""Should parse benchmarksRoot from codeflash config."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test", "codeflash": {"benchmarksRoot": "__benchmarks__"}}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["benchmarks_root"] == str((tmp_path / "__benchmarks__").resolve())
|
||||
|
||||
def test_parses_disable_telemetry(self, tmp_path: Path) -> None:
|
||||
"""Should parse disableTelemetry from codeflash config."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test", "codeflash": {"disableTelemetry": True}}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["disable_telemetry"] is True
|
||||
|
||||
def test_defaults_disable_telemetry_to_false(self, tmp_path: Path) -> None:
|
||||
"""Should default disableTelemetry to False."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test"}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["disable_telemetry"] is False
|
||||
|
||||
def test_sets_backwards_compat_defaults(self, tmp_path: Path) -> None:
|
||||
"""Should set backwards compatibility defaults."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test"}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["git_remote"] == "origin"
|
||||
assert config["disable_imports_sorting"] is False
|
||||
assert config["override_fixtures"] is False
|
||||
|
||||
def test_returns_none_for_invalid_json(self, tmp_path: Path) -> None:
|
||||
"""Should return None for invalid JSON."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text("invalid json")
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_handles_non_dict_codeflash_config(self, tmp_path: Path) -> None:
|
||||
"""Should handle non-dict codeflash section."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test", "codeflash": "invalid"}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
# Should use auto-detected/default values
|
||||
assert "language" in config
|
||||
|
||||
def test_empty_formatter_when_none_detected(self, tmp_path: Path) -> None:
|
||||
"""Should have empty formatter_cmds when no formatter detected."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test", "devDependencies": {"typescript": "^5.0.0"}}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["formatter_cmds"] == []
|
||||
|
||||
def test_parses_git_remote_from_config(self, tmp_path: Path) -> None:
|
||||
"""Should parse gitRemote from codeflash config."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test", "codeflash": {"gitRemote": "upstream"}}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["git_remote"] == "upstream"
|
||||
|
||||
def test_defaults_git_remote_to_origin(self, tmp_path: Path) -> None:
|
||||
"""Should default gitRemote to 'origin' when not specified."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test"}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["git_remote"] == "origin"
|
||||
|
||||
def test_handles_empty_git_remote(self, tmp_path: Path) -> None:
|
||||
"""Should handle empty gitRemote in config."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test", "codeflash": {"gitRemote": ""}}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
# Empty string should be treated as the value (not defaulted to origin)
|
||||
assert config["git_remote"] == ""
|
||||
|
||||
|
||||
class TestClearCache:
|
||||
"""Tests for clear_cache function."""
|
||||
|
||||
def test_clears_both_caches(self, tmp_path: Path) -> None:
|
||||
"""Should clear both path and data caches."""
|
||||
# Populate caches
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test"}))
|
||||
get_package_json_data(package_json)
|
||||
|
||||
assert len(PACKAGE_JSON_DATA_CACHE) > 0
|
||||
|
||||
clear_cache()
|
||||
|
||||
assert len(PACKAGE_JSON_CACHE) == 0
|
||||
assert len(PACKAGE_JSON_DATA_CACHE) == 0
|
||||
|
||||
|
||||
class TestRealWorldPackageJsonExamples:
|
||||
"""Tests with real-world-like package.json configurations."""
|
||||
|
||||
def test_nextjs_project(self, tmp_path: Path) -> None:
|
||||
"""Should handle Next.js project configuration."""
|
||||
(tmp_path / "src").mkdir()
|
||||
(tmp_path / "tsconfig.json").write_text("{}")
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"name": "my-nextjs-app",
|
||||
"scripts": {"test": "jest"},
|
||||
"devDependencies": {"jest": "^29.0.0", "prettier": "^3.0.0", "typescript": "^5.0.0"},
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["language"] == "typescript"
|
||||
assert config["module_root"] == str((tmp_path / "src").resolve())
|
||||
assert config["test_runner"] == "jest"
|
||||
assert config["formatter_cmds"] == ["npx prettier --write $file"]
|
||||
|
||||
def test_vite_react_project(self, tmp_path: Path) -> None:
|
||||
"""Should handle Vite + React project configuration."""
|
||||
(tmp_path / "src").mkdir()
|
||||
(tmp_path / "tsconfig.json").write_text("{}")
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"name": "vite-react-app",
|
||||
"type": "module",
|
||||
"scripts": {"test": "vitest"},
|
||||
"devDependencies": {"vitest": "^1.0.0", "eslint": "^8.0.0"},
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["language"] == "typescript"
|
||||
assert config["test_runner"] == "vitest"
|
||||
assert config["formatter_cmds"] == ["npx eslint --fix $file"]
|
||||
|
||||
def test_library_with_exports(self, tmp_path: Path) -> None:
|
||||
"""Should handle library with modern exports field."""
|
||||
(tmp_path / "dist").mkdir()
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"name": "my-library",
|
||||
"exports": {".": {"import": "./dist/index.mjs", "require": "./dist/index.cjs"}},
|
||||
"devDependencies": {"vitest": "^1.0.0", "prettier": "^3.0.0"},
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["module_root"] == str((tmp_path / "dist").resolve())
|
||||
|
||||
def test_monorepo_package(self, tmp_path: Path) -> None:
|
||||
"""Should handle monorepo package configuration."""
|
||||
(tmp_path / "packages" / "core" / "src").mkdir(parents=True)
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"name": "@myorg/core",
|
||||
"main": "./packages/core/src/index.js",
|
||||
"devDependencies": {"jest": "^29.0.0"},
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["module_root"] == str((tmp_path / "packages/core/src").resolve())
|
||||
|
||||
def test_node_cli_project(self, tmp_path: Path) -> None:
|
||||
"""Should handle Node.js CLI project."""
|
||||
(tmp_path / "bin").mkdir()
|
||||
(tmp_path / "lib").mkdir()
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"name": "my-cli",
|
||||
"bin": {"my-cli": "./bin/cli.js"},
|
||||
"main": "./lib/index.js",
|
||||
"devDependencies": {"mocha": "^10.0.0"},
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["module_root"] == str((tmp_path / "lib").resolve())
|
||||
assert config["test_runner"] == "mocha"
|
||||
|
||||
def test_minimal_project(self, tmp_path: Path) -> None:
|
||||
"""Should handle minimal package.json."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "minimal"}))
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["language"] == "javascript"
|
||||
assert config["module_root"] == str(tmp_path.resolve())
|
||||
assert config["test_runner"] == "jest"
|
||||
assert config["formatter_cmds"] == []
|
||||
|
||||
def test_existing_codeflash_config_with_overrides(self, tmp_path: Path) -> None:
|
||||
"""Should handle existing codeflash config with custom overrides."""
|
||||
(tmp_path / "custom-src").mkdir()
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"name": "configured-project",
|
||||
"devDependencies": {"jest": "^29.0.0", "prettier": "^3.0.0"},
|
||||
"codeflash": {
|
||||
"moduleRoot": "custom-src",
|
||||
"formatterCmds": ["npx prettier --write --single-quote $file"],
|
||||
"ignorePaths": ["dist", "coverage"],
|
||||
"disableTelemetry": True,
|
||||
},
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
result = parse_package_json_config(package_json)
|
||||
|
||||
assert result is not None
|
||||
config, _ = result
|
||||
assert config["module_root"] == str((tmp_path / "custom-src").resolve())
|
||||
assert config["formatter_cmds"] == ["npx prettier --write --single-quote $file"]
|
||||
assert len(config["ignore_paths"]) == 2
|
||||
assert config["disable_telemetry"] is True
|
||||
238
tests/code_utils/test_js_workflow_helpers.py
Normal file
238
tests/code_utils/test_js_workflow_helpers.py
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
"""Tests for JavaScript/TypeScript GitHub Actions workflow helpers."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from codeflash.cli_cmds.init_javascript import (
|
||||
JsPackageManager,
|
||||
get_js_codeflash_install_step,
|
||||
get_js_codeflash_run_command,
|
||||
get_js_dependency_installation_commands,
|
||||
get_js_runtime_setup_steps,
|
||||
is_codeflash_dependency,
|
||||
)
|
||||
|
||||
|
||||
class TestIsCodeflashDependency:
|
||||
"""Tests for is_codeflash_dependency function."""
|
||||
|
||||
def test_returns_true_when_in_dev_dependencies(self, tmp_path: Path) -> None:
|
||||
"""Should return True when codeflash is in devDependencies."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"devDependencies": {"codeflash": "^1.0.0"}}))
|
||||
|
||||
assert is_codeflash_dependency(tmp_path) is True
|
||||
|
||||
def test_returns_true_when_in_dependencies(self, tmp_path: Path) -> None:
|
||||
"""Should return True when codeflash is in dependencies."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"dependencies": {"codeflash": "^1.0.0"}}))
|
||||
|
||||
assert is_codeflash_dependency(tmp_path) is True
|
||||
|
||||
def test_returns_false_when_not_present(self, tmp_path: Path) -> None:
|
||||
"""Should return False when codeflash is not in any dependencies."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"devDependencies": {"jest": "^29.0.0"}}))
|
||||
|
||||
assert is_codeflash_dependency(tmp_path) is False
|
||||
|
||||
def test_returns_false_when_no_package_json(self, tmp_path: Path) -> None:
|
||||
"""Should return False when package.json doesn't exist."""
|
||||
assert is_codeflash_dependency(tmp_path) is False
|
||||
|
||||
def test_returns_false_for_invalid_json(self, tmp_path: Path) -> None:
|
||||
"""Should return False for invalid package.json."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text("invalid json")
|
||||
|
||||
assert is_codeflash_dependency(tmp_path) is False
|
||||
|
||||
def test_handles_empty_dependencies(self, tmp_path: Path) -> None:
|
||||
"""Should handle empty dependencies objects."""
|
||||
package_json = tmp_path / "package.json"
|
||||
package_json.write_text(json.dumps({"name": "test", "dependencies": {}, "devDependencies": {}}))
|
||||
|
||||
assert is_codeflash_dependency(tmp_path) is False
|
||||
|
||||
|
||||
class TestGetJsRuntimeSetupSteps:
|
||||
"""Tests for get_js_runtime_setup_steps function."""
|
||||
|
||||
def test_npm_setup(self) -> None:
|
||||
"""Should generate correct setup steps for npm."""
|
||||
result = get_js_runtime_setup_steps(JsPackageManager.NPM)
|
||||
|
||||
assert "Setup Node.js" in result
|
||||
assert "actions/setup-node@v4" in result
|
||||
assert "node-version: '22'" in result
|
||||
assert "cache: 'npm'" in result
|
||||
|
||||
def test_yarn_setup(self) -> None:
|
||||
"""Should generate correct setup steps for yarn."""
|
||||
result = get_js_runtime_setup_steps(JsPackageManager.YARN)
|
||||
|
||||
assert "Setup Node.js" in result
|
||||
assert "actions/setup-node@v4" in result
|
||||
assert "cache: 'yarn'" in result
|
||||
|
||||
def test_pnpm_setup(self) -> None:
|
||||
"""Should generate correct setup steps for pnpm."""
|
||||
result = get_js_runtime_setup_steps(JsPackageManager.PNPM)
|
||||
|
||||
assert "Setup pnpm" in result
|
||||
assert "pnpm/action-setup@v4" in result
|
||||
assert "Setup Node.js" in result
|
||||
assert "cache: 'pnpm'" in result
|
||||
|
||||
def test_bun_setup(self) -> None:
|
||||
"""Should generate correct setup steps for bun."""
|
||||
result = get_js_runtime_setup_steps(JsPackageManager.BUN)
|
||||
|
||||
assert "Setup Bun" in result
|
||||
assert "oven-sh/setup-bun@v2" in result
|
||||
assert "bun-version: latest" in result
|
||||
|
||||
def test_unknown_defaults_to_npm(self) -> None:
|
||||
"""Should default to npm setup for unknown package manager."""
|
||||
result = get_js_runtime_setup_steps(JsPackageManager.UNKNOWN)
|
||||
|
||||
assert "cache: 'npm'" in result
|
||||
|
||||
|
||||
class TestGetJsDependencyInstallationCommands:
|
||||
"""Tests for get_js_dependency_installation_commands function."""
|
||||
|
||||
def test_npm_install(self) -> None:
|
||||
"""Should return npm ci for npm."""
|
||||
assert get_js_dependency_installation_commands(JsPackageManager.NPM) == "npm ci"
|
||||
|
||||
def test_yarn_install(self) -> None:
|
||||
"""Should return yarn install for yarn."""
|
||||
assert get_js_dependency_installation_commands(JsPackageManager.YARN) == "yarn install"
|
||||
|
||||
def test_pnpm_install(self) -> None:
|
||||
"""Should return pnpm install for pnpm."""
|
||||
assert get_js_dependency_installation_commands(JsPackageManager.PNPM) == "pnpm install"
|
||||
|
||||
def test_bun_install(self) -> None:
|
||||
"""Should return bun install for bun."""
|
||||
assert get_js_dependency_installation_commands(JsPackageManager.BUN) == "bun install"
|
||||
|
||||
|
||||
class TestGetJsCodeflashInstallStep:
|
||||
"""Tests for get_js_codeflash_install_step function."""
|
||||
|
||||
def test_returns_empty_when_is_dependency(self) -> None:
|
||||
"""Should return empty string when codeflash is a dependency."""
|
||||
result = get_js_codeflash_install_step(JsPackageManager.NPM, is_dependency=True)
|
||||
|
||||
assert result == ""
|
||||
|
||||
def test_npm_global_install(self) -> None:
|
||||
"""Should generate npm global install when not a dependency."""
|
||||
result = get_js_codeflash_install_step(JsPackageManager.NPM, is_dependency=False)
|
||||
|
||||
assert "Install Codeflash" in result
|
||||
assert "npm install -g codeflash" in result
|
||||
|
||||
def test_yarn_global_install(self) -> None:
|
||||
"""Should generate yarn global install when not a dependency."""
|
||||
result = get_js_codeflash_install_step(JsPackageManager.YARN, is_dependency=False)
|
||||
|
||||
assert "yarn global add codeflash" in result
|
||||
|
||||
def test_pnpm_global_install(self) -> None:
|
||||
"""Should generate pnpm global install when not a dependency."""
|
||||
result = get_js_codeflash_install_step(JsPackageManager.PNPM, is_dependency=False)
|
||||
|
||||
assert "pnpm add -g codeflash" in result
|
||||
|
||||
def test_bun_global_install(self) -> None:
|
||||
"""Should generate bun global install when not a dependency."""
|
||||
result = get_js_codeflash_install_step(JsPackageManager.BUN, is_dependency=False)
|
||||
|
||||
assert "bun add -g codeflash" in result
|
||||
|
||||
|
||||
class TestGetJsCodeflashRunCommand:
|
||||
"""Tests for get_js_codeflash_run_command function."""
|
||||
|
||||
def test_npm_with_dependency(self) -> None:
|
||||
"""Should use npx when codeflash is a dependency."""
|
||||
result = get_js_codeflash_run_command(JsPackageManager.NPM, is_dependency=True)
|
||||
|
||||
assert result == "npx codeflash"
|
||||
|
||||
def test_npm_without_dependency(self) -> None:
|
||||
"""Should use direct codeflash when globally installed."""
|
||||
result = get_js_codeflash_run_command(JsPackageManager.NPM, is_dependency=False)
|
||||
|
||||
assert result == "codeflash"
|
||||
|
||||
def test_yarn_with_dependency(self) -> None:
|
||||
"""Should use yarn codeflash when it's a dependency."""
|
||||
result = get_js_codeflash_run_command(JsPackageManager.YARN, is_dependency=True)
|
||||
|
||||
assert result == "yarn codeflash"
|
||||
|
||||
def test_pnpm_with_dependency(self) -> None:
|
||||
"""Should use pnpm exec when it's a dependency."""
|
||||
result = get_js_codeflash_run_command(JsPackageManager.PNPM, is_dependency=True)
|
||||
|
||||
assert result == "pnpm exec codeflash"
|
||||
|
||||
def test_bun_with_dependency(self) -> None:
|
||||
"""Should use bun run when it's a dependency."""
|
||||
result = get_js_codeflash_run_command(JsPackageManager.BUN, is_dependency=True)
|
||||
|
||||
assert result == "bun run codeflash"
|
||||
|
||||
def test_all_global_installs_use_direct_command(self) -> None:
|
||||
"""All package managers should use direct 'codeflash' when globally installed."""
|
||||
for pm in [JsPackageManager.NPM, JsPackageManager.YARN, JsPackageManager.PNPM, JsPackageManager.BUN]:
|
||||
result = get_js_codeflash_run_command(pm, is_dependency=False)
|
||||
assert result == "codeflash", f"Failed for {pm}"
|
||||
|
||||
|
||||
class TestWorkflowTemplateIntegration:
|
||||
"""Integration tests for workflow template generation."""
|
||||
|
||||
def test_workflow_template_exists(self) -> None:
|
||||
"""Verify the JS workflow template file exists."""
|
||||
from importlib.resources import files
|
||||
|
||||
template_path = files("codeflash").joinpath("cli_cmds", "workflows", "codeflash-optimize-js.yaml")
|
||||
content = template_path.read_text(encoding="utf-8")
|
||||
|
||||
# Check all placeholders exist
|
||||
assert "{{ codeflash_module_path }}" in content
|
||||
assert "{{ working_directory }}" in content
|
||||
assert "{{ setup_runtime_steps }}" in content
|
||||
assert "{{ install_dependencies_command }}" in content
|
||||
assert "{{ install_codeflash_step }}" in content
|
||||
assert "{{ codeflash_command }}" in content
|
||||
|
||||
def test_workflow_template_has_correct_structure(self) -> None:
|
||||
"""Verify the JS workflow template has the expected YAML structure."""
|
||||
from importlib.resources import files
|
||||
|
||||
template_path = files("codeflash").joinpath("cli_cmds", "workflows", "codeflash-optimize-js.yaml")
|
||||
content = template_path.read_text(encoding="utf-8")
|
||||
|
||||
# Check key sections
|
||||
assert "name: Codeflash" in content
|
||||
assert "pull_request:" in content
|
||||
assert "workflow_dispatch:" in content
|
||||
assert "concurrency:" in content
|
||||
assert "cancel-in-progress: true" in content
|
||||
assert "jobs:" in content
|
||||
assert "optimize:" in content
|
||||
assert "github.actor != 'codeflash-ai[bot]'" in content
|
||||
assert "CODEFLASH_API_KEY" in content
|
||||
assert "actions/checkout@v4" in content
|
||||
assert "fetch-depth: 0" in content
|
||||
32
tests/scripts/end_to_end_test_js_cjs_function.py
Normal file
32
tests/scripts/end_to_end_test_js_cjs_function.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
"""End-to-end test for JavaScript CommonJS optimization.
|
||||
|
||||
Tests optimization of a simple recursive fibonacci function using CommonJS module format.
|
||||
"""
|
||||
|
||||
import pathlib
|
||||
|
||||
from end_to_end_test_utilities_js import JSTestConfig, run_js_codeflash_command, run_with_retries
|
||||
|
||||
|
||||
def run_test() -> bool:
|
||||
"""Run the CommonJS fibonacci optimization test."""
|
||||
config = JSTestConfig(
|
||||
file_path=pathlib.Path("fibonacci.js"),
|
||||
function_name="fibonacci",
|
||||
min_improvement_x=0.5, # Expect at least 50% improvement
|
||||
expected_improvement_pct=50,
|
||||
expected_test_files=1,
|
||||
)
|
||||
|
||||
cwd = (
|
||||
pathlib.Path(__file__).parent.parent.parent
|
||||
/ "code_to_optimize"
|
||||
/ "js"
|
||||
/ "code_to_optimize_js"
|
||||
).resolve()
|
||||
|
||||
return run_js_codeflash_command(cwd, config)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(run_with_retries(run_test))
|
||||
33
tests/scripts/end_to_end_test_js_esm_async.py
Normal file
33
tests/scripts/end_to_end_test_js_esm_async.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
"""End-to-end test for JavaScript ES Modules async function optimization.
|
||||
|
||||
Tests optimization of async functions using ES Module format.
|
||||
This tests the ESM module system with async/await code patterns.
|
||||
"""
|
||||
|
||||
import pathlib
|
||||
|
||||
from end_to_end_test_utilities_js import JSTestConfig, run_js_codeflash_command, run_with_retries
|
||||
|
||||
|
||||
def run_test() -> bool:
|
||||
"""Run the ES Modules async function optimization test."""
|
||||
config = JSTestConfig(
|
||||
file_path=pathlib.Path("async_utils.js"),
|
||||
function_name="processItemsSequential",
|
||||
min_improvement_x=0.1, # Async optimizations may have variable gains
|
||||
expected_improvement_pct=10,
|
||||
expected_test_files=1,
|
||||
)
|
||||
|
||||
cwd = (
|
||||
pathlib.Path(__file__).parent.parent.parent
|
||||
/ "code_to_optimize"
|
||||
/ "js"
|
||||
/ "code_to_optimize_js_esm"
|
||||
).resolve()
|
||||
|
||||
return run_js_codeflash_command(cwd, config)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(run_with_retries(run_test))
|
||||
32
tests/scripts/end_to_end_test_js_ts_class.py
Normal file
32
tests/scripts/end_to_end_test_js_ts_class.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
"""End-to-end test for TypeScript class method optimization.
|
||||
|
||||
Tests optimization of class methods in TypeScript.
|
||||
"""
|
||||
|
||||
import pathlib
|
||||
|
||||
from end_to_end_test_utilities_js import JSTestConfig, run_js_codeflash_command, run_with_retries
|
||||
|
||||
|
||||
def run_test() -> bool:
|
||||
"""Run the TypeScript class method optimization test."""
|
||||
config = JSTestConfig(
|
||||
file_path=pathlib.Path("data_processor.ts"),
|
||||
function_name="DataProcessor.findDuplicates",
|
||||
min_improvement_x=0.3, # Expect at least 30% improvement
|
||||
expected_improvement_pct=30,
|
||||
expected_test_files=1,
|
||||
)
|
||||
|
||||
cwd = (
|
||||
pathlib.Path(__file__).parent.parent.parent
|
||||
/ "code_to_optimize"
|
||||
/ "js"
|
||||
/ "code_to_optimize_ts"
|
||||
).resolve()
|
||||
|
||||
return run_js_codeflash_command(cwd, config)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(run_with_retries(run_test))
|
||||
213
tests/scripts/end_to_end_test_utilities_js.py
Normal file
213
tests/scripts/end_to_end_test_utilities_js.py
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
"""End-to-end test utilities for JavaScript/TypeScript optimization testing.
|
||||
|
||||
Similar to end_to_end_test_utilities.py but adapted for JS/TS projects.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class JSTestConfig:
|
||||
"""Configuration for a JavaScript/TypeScript e2e test."""
|
||||
|
||||
# Path to the source file to optimize (relative to project root)
|
||||
file_path: pathlib.Path
|
||||
# Function name to optimize (optional - if not specified, optimizes all in file)
|
||||
function_name: Optional[str] = None
|
||||
# Minimum improvement multiplier (e.g., 0.5 = 50% faster)
|
||||
min_improvement_x: float = 0.1
|
||||
# Expected improvement percentage (optimization must exceed this)
|
||||
expected_improvement_pct: int = 10
|
||||
# Expected number of test files discovered
|
||||
expected_test_files: Optional[int] = None
|
||||
|
||||
|
||||
def clear_codeflash_directory(cwd: pathlib.Path) -> None:
|
||||
"""Clear the .codeflash directory to avoid stale state."""
|
||||
codeflash_dir = cwd / ".codeflash"
|
||||
if codeflash_dir.exists():
|
||||
shutil.rmtree(codeflash_dir)
|
||||
|
||||
|
||||
def install_npm_dependencies(cwd: pathlib.Path) -> bool:
|
||||
"""Install npm dependencies if needed."""
|
||||
node_modules = cwd / "node_modules"
|
||||
if not node_modules.exists():
|
||||
logging.info(f"Installing npm dependencies in {cwd}")
|
||||
result = subprocess.run(
|
||||
["npm", "install"],
|
||||
cwd=str(cwd),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
logging.error(f"npm install failed: {result.stderr}")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def build_js_command(
|
||||
cwd: pathlib.Path,
|
||||
config: JSTestConfig,
|
||||
) -> list[str]:
|
||||
"""Build the codeflash CLI command for JS/TS optimization."""
|
||||
# Use relative path for python to find the main module
|
||||
python_path = "../../codeflash/main.py"
|
||||
if "code_to_optimize_js" in str(cwd):
|
||||
python_path = "../../../../codeflash/main.py"
|
||||
|
||||
base_command = [
|
||||
"uv",
|
||||
"run",
|
||||
"--no-project",
|
||||
python_path,
|
||||
"--file",
|
||||
str(config.file_path),
|
||||
"--no-pr",
|
||||
]
|
||||
|
||||
if config.function_name:
|
||||
base_command.extend(["--function", config.function_name])
|
||||
|
||||
return base_command
|
||||
|
||||
|
||||
def validate_js_output(
|
||||
stdout: str,
|
||||
return_code: int,
|
||||
config: JSTestConfig,
|
||||
) -> bool:
|
||||
"""Validate the output of a JS/TS optimization run."""
|
||||
if return_code != 0:
|
||||
logging.error(f"Command returned exit code {return_code} instead of 0")
|
||||
return False
|
||||
|
||||
if "⚡️ Optimization successful! 📄 " not in stdout:
|
||||
logging.error("Failed to find performance improvement message")
|
||||
return False
|
||||
|
||||
improvement_match = re.search(r"📈 ([\d,]+)% (?:(\w+) )?improvement", stdout)
|
||||
if not improvement_match:
|
||||
logging.error("Could not find improvement percentage in output")
|
||||
return False
|
||||
|
||||
improvement_pct = int(improvement_match.group(1).replace(",", ""))
|
||||
improvement_x = float(improvement_pct) / 100
|
||||
|
||||
logging.info(f"Performance improvement: {improvement_pct}%; Rate: {improvement_x}x")
|
||||
|
||||
if improvement_pct <= config.expected_improvement_pct:
|
||||
logging.error(
|
||||
f"Performance improvement {improvement_pct}% not above {config.expected_improvement_pct}%"
|
||||
)
|
||||
return False
|
||||
|
||||
if improvement_x <= config.min_improvement_x:
|
||||
logging.error(
|
||||
f"Performance improvement rate {improvement_x}x not above {config.min_improvement_x}x"
|
||||
)
|
||||
return False
|
||||
|
||||
if config.expected_test_files is not None:
|
||||
test_files_match = re.search(r"Discovered (\d+) existing unit test files?", stdout)
|
||||
if not test_files_match:
|
||||
logging.error("Could not find unit test file count")
|
||||
return False
|
||||
|
||||
num_test_files = int(test_files_match.group(1))
|
||||
if num_test_files != config.expected_test_files:
|
||||
logging.error(
|
||||
f"Expected {config.expected_test_files} test files, found {num_test_files}"
|
||||
)
|
||||
return False
|
||||
|
||||
logging.info(f"Success: Performance improvement is {improvement_pct}%")
|
||||
return True
|
||||
|
||||
|
||||
def run_js_codeflash_command(
|
||||
cwd: pathlib.Path,
|
||||
config: JSTestConfig,
|
||||
) -> bool:
|
||||
"""Run codeflash optimization on a JavaScript/TypeScript project."""
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
# Save original file contents for potential revert
|
||||
path_to_file = cwd / config.file_path
|
||||
file_contents = path_to_file.read_text("utf-8")
|
||||
|
||||
# Clear any stale state
|
||||
clear_codeflash_directory(cwd)
|
||||
|
||||
# Install dependencies if needed
|
||||
if not install_npm_dependencies(cwd):
|
||||
return False
|
||||
|
||||
# Build and run command
|
||||
command = build_js_command(cwd, config)
|
||||
env = os.environ.copy()
|
||||
env["PYTHONIOENCODING"] = "utf-8"
|
||||
|
||||
logging.info(f"Running: {' '.join(command)}")
|
||||
|
||||
process = subprocess.Popen(
|
||||
command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
cwd=str(cwd),
|
||||
env=env,
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
output = []
|
||||
for line in process.stdout:
|
||||
logging.info(line.strip())
|
||||
output.append(line)
|
||||
|
||||
return_code = process.wait()
|
||||
stdout = "".join(output)
|
||||
|
||||
validated = validate_js_output(stdout, return_code, config)
|
||||
if not validated:
|
||||
# Revert file changes on failure
|
||||
path_to_file.write_text(file_contents, "utf-8")
|
||||
logging.info("Codeflash run did not meet expected requirements, reverting file changes.")
|
||||
return False
|
||||
|
||||
return validated
|
||||
|
||||
|
||||
def run_with_retries(test_func, *args, **kwargs) -> int:
|
||||
"""Run a test function with retries on failure."""
|
||||
max_retries = int(os.getenv("MAX_RETRIES", 3))
|
||||
retry_delay = int(os.getenv("RETRY_DELAY", 5))
|
||||
|
||||
log = logging.getLogger()
|
||||
log.setLevel(logging.DEBUG)
|
||||
|
||||
for attempt in range(1, max_retries + 1):
|
||||
logging.info(f"\n=== Attempt {attempt} of {max_retries} ===")
|
||||
|
||||
if test_func(*args, **kwargs):
|
||||
logging.info(f"Test passed on attempt {attempt}")
|
||||
return 0
|
||||
|
||||
logging.error(f"Test failed on attempt {attempt}")
|
||||
|
||||
if attempt < max_retries:
|
||||
logging.info(f"Retrying in {retry_delay} seconds...")
|
||||
time.sleep(retry_delay)
|
||||
else:
|
||||
logging.error("Test failed after all retries")
|
||||
return 1
|
||||
|
||||
return 1
|
||||
171
tests/scripts/run_js_e2e_tests.py
Normal file
171
tests/scripts/run_js_e2e_tests.py
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Runner script for all JavaScript/TypeScript end-to-end tests.
|
||||
|
||||
This script runs all JS/TS e2e tests and reports results.
|
||||
Usage:
|
||||
python run_js_e2e_tests.py [--test TEST_NAME] [--parallel]
|
||||
|
||||
Examples:
|
||||
python run_js_e2e_tests.py # Run all tests sequentially
|
||||
python run_js_e2e_tests.py --test fibonacci # Run only fibonacci tests
|
||||
python run_js_e2e_tests.py --parallel # Run tests in parallel
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from concurrent.futures import ProcessPoolExecutor, as_completed
|
||||
from pathlib import Path
|
||||
from typing import NamedTuple
|
||||
|
||||
|
||||
class TestResult(NamedTuple):
|
||||
name: str
|
||||
success: bool
|
||||
duration: float
|
||||
output: str
|
||||
|
||||
|
||||
# List of all JS/TS e2e tests - one per module type, each testing different code patterns
|
||||
JS_E2E_TESTS = [
|
||||
# CommonJS - Simple function optimization (recursive fibonacci)
|
||||
"end_to_end_test_js_cjs_function.py",
|
||||
# TypeScript - Class method optimization (DataProcessor.findDuplicates)
|
||||
"end_to_end_test_js_ts_class.py",
|
||||
# ES Modules - Async function optimization (processItemsSequential)
|
||||
"end_to_end_test_js_esm_async.py",
|
||||
]
|
||||
|
||||
|
||||
def run_single_test(test_file: str) -> TestResult:
|
||||
"""Run a single test and return the result."""
|
||||
script_dir = Path(__file__).parent
|
||||
test_path = script_dir / test_file
|
||||
|
||||
start_time = time.time()
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["python", str(test_path)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=600, # 10 minute timeout
|
||||
cwd=str(script_dir),
|
||||
)
|
||||
success = result.returncode == 0
|
||||
output = result.stdout + result.stderr
|
||||
except subprocess.TimeoutExpired:
|
||||
success = False
|
||||
output = "Test timed out after 600 seconds"
|
||||
except Exception as e:
|
||||
success = False
|
||||
output = f"Error running test: {e}"
|
||||
|
||||
duration = time.time() - start_time
|
||||
return TestResult(
|
||||
name=test_file.replace(".py", ""),
|
||||
success=success,
|
||||
duration=duration,
|
||||
output=output,
|
||||
)
|
||||
|
||||
|
||||
def run_tests_sequential(tests: list[str]) -> list[TestResult]:
|
||||
"""Run tests sequentially."""
|
||||
results = []
|
||||
for test in tests:
|
||||
print(f"\n{'='*60}")
|
||||
print(f"Running: {test}")
|
||||
print("=" * 60)
|
||||
result = run_single_test(test)
|
||||
results.append(result)
|
||||
status = "✅ PASSED" if result.success else "❌ FAILED"
|
||||
print(f"{status} in {result.duration:.1f}s")
|
||||
if not result.success:
|
||||
print(f"Output:\n{result.output}")
|
||||
return results
|
||||
|
||||
|
||||
def run_tests_parallel(tests: list[str], max_workers: int = 4) -> list[TestResult]:
|
||||
"""Run tests in parallel."""
|
||||
results = []
|
||||
with ProcessPoolExecutor(max_workers=max_workers) as executor:
|
||||
futures = {executor.submit(run_single_test, test): test for test in tests}
|
||||
for future in as_completed(futures):
|
||||
test = futures[future]
|
||||
result = future.result()
|
||||
results.append(result)
|
||||
status = "✅ PASSED" if result.success else "❌ FAILED"
|
||||
print(f"{status}: {result.name} ({result.duration:.1f}s)")
|
||||
return results
|
||||
|
||||
|
||||
def print_summary(results: list[TestResult]) -> None:
|
||||
"""Print a summary of test results."""
|
||||
print("\n" + "=" * 60)
|
||||
print("TEST SUMMARY")
|
||||
print("=" * 60)
|
||||
|
||||
passed = [r for r in results if r.success]
|
||||
failed = [r for r in results if not r.success]
|
||||
|
||||
print(f"\nTotal: {len(results)}")
|
||||
print(f"Passed: {len(passed)}")
|
||||
print(f"Failed: {len(failed)}")
|
||||
|
||||
if failed:
|
||||
print("\nFailed tests:")
|
||||
for r in failed:
|
||||
print(f" ❌ {r.name}")
|
||||
|
||||
total_duration = sum(r.duration for r in results)
|
||||
print(f"\nTotal duration: {total_duration:.1f}s")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Run JS/TS e2e tests")
|
||||
parser.add_argument(
|
||||
"--test",
|
||||
type=str,
|
||||
help="Run only tests matching this pattern",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--parallel",
|
||||
action="store_true",
|
||||
help="Run tests in parallel",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--workers",
|
||||
type=int,
|
||||
default=4,
|
||||
help="Number of parallel workers (default: 4)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Filter tests if pattern specified
|
||||
tests = JS_E2E_TESTS
|
||||
if args.test:
|
||||
tests = [t for t in tests if args.test.lower() in t.lower()]
|
||||
|
||||
if not tests:
|
||||
print(f"No tests matching pattern: {args.test}")
|
||||
return 1
|
||||
|
||||
print(f"Running {len(tests)} test(s)...")
|
||||
|
||||
# Run tests
|
||||
if args.parallel:
|
||||
results = run_tests_parallel(tests, args.workers)
|
||||
else:
|
||||
results = run_tests_sequential(tests)
|
||||
|
||||
# Print summary
|
||||
print_summary(results)
|
||||
|
||||
# Return exit code
|
||||
failed = [r for r in results if not r.success]
|
||||
return 1 if failed else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Loading…
Reference in a new issue