local-leetcode-trainer
Version:
A complete local LeetCode practice environment with multi-language support - use your IDE, collaborate with AI, submit with confidence
379 lines (327 loc) • 10.1 kB
JavaScript
const fs = require('fs');
const path = require('path');
const readline = require('readline');
// Supported languages configuration
const LANGUAGE_CONFIGS = {
javascript: {
extension: '.js',
testCommand: 'node',
template: `/**
* {{id}}. {{title}}
* {{leetcodeUrl}}
*
* {{description}}
*
* {{examples}}
*
* Constraints:
{{constraints}}
*
* @param {{jsDocParams}}
* @return {{jsDocReturn}}
*/
var {{functionName}} = function({{functionParams}}) {
};
module.exports = {{functionName}};`,
testTemplate: `// Test cases for {{title}}
// TODO: Add test cases from LeetCode problem description
module.exports = [
{
input: [],
expected: null
}
];`
},
python: {
extension: '.py',
testCommand: 'python3',
template: `"""
LeetCode {{id}}: {{title}}
Link: https://leetcode.com/problems/{{name}}/
{{description}}
Topics: {{topics}}
Companies: {{companies}}
TODO: Add problem description, examples, and constraints from LeetCode
"""
def {{function_name}}():
# Your solution here
pass
if __name__ == "__main__":
# Test runner will execute this
pass`,
testTemplate: `# Test cases for {{title}}
# TODO: Add test cases from LeetCode problem description
test_cases = [
{
"input": [],
"expected": None
}
]`
},
java: {
extension: '.java',
testCommand: 'javac {{file}} && java {{className}}',
template: `/**
* LeetCode {{id}}: {{title}}
* Link: https://leetcode.com/problems/{{name}}/
*
* {{description}}
*
* Topics: {{topics}}
* Companies: {{companies}}
*
* TODO: Add problem description, examples, and constraints from LeetCode
*/
public class {{ClassName}} {
public static void main(String[] args) {
// Your solution here
}
}`,
testTemplate: `// Test cases for {{title}}
// TODO: Add test cases from LeetCode problem description
public class {{ClassName}}Test {
// Test implementation
}`
},
cpp: {
extension: '.cpp',
testCommand: 'g++ -o {{output}} {{file}} && ./{{output}}',
template: `/**
* LeetCode {{id}}: {{title}}
* Link: https://leetcode.com/problems/{{name}}/
*
* {{description}}
*
* Topics: {{topics}}
* Companies: {{companies}}
*
* TODO: Add problem description, examples, and constraints from LeetCode
*/
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
// Your solution here
};
int main() {
// Test cases
return 0;
}`,
testTemplate: `// Test cases for {{title}}
// TODO: Add test cases from LeetCode problem description`
}
};
// Config file path - now in user's project directory
const CONFIG_FILE = path.join(process.cwd(), 'lct', 'config.json');
// Read current configuration
function readConfig() {
try {
if (fs.existsSync(CONFIG_FILE)) {
const content = fs.readFileSync(CONFIG_FILE, 'utf8');
return JSON.parse(content);
}
} catch (error) {
console.log('⚠️ Config file corrupted, using defaults');
}
// Default configuration
return {
language: 'javascript',
companies: [],
createdAt: new Date().toISOString()
};
}
// Write configuration
function writeConfig(config) {
try {
// Ensure lct directory exists
const lctDir = path.dirname(CONFIG_FILE);
if (!fs.existsSync(lctDir)) {
fs.mkdirSync(lctDir, { recursive: true });
}
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
return true;
} catch (error) {
console.log(`❌ Failed to write config: ${error.message}`);
console.log('💡 Try running "lct init" first to set up your project');
return false;
}
}
// Get current language
function getCurrentLanguage() {
const config = readConfig();
return config.language || 'javascript';
}
// Get language configuration
function getLanguageConfig(language) {
return LANGUAGE_CONFIGS[language] || LANGUAGE_CONFIGS.javascript;
}
// Ask for user confirmation
function askConfirmation(question) {
return new Promise((resolve) => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question(`${question} (y/N): `, (answer) => {
rl.close();
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
});
});
}
// Count problems in workspace
function countProblems() {
const counts = { easy: 0, medium: 0, hard: 0 };
['easy', 'medium', 'hard'].forEach(difficulty => {
const difficultyPath = path.join(process.cwd(), difficulty);
if (fs.existsSync(difficultyPath)) {
const items = fs.readdirSync(difficultyPath);
items.forEach(item => {
const itemPath = path.join(difficultyPath, item);
if (fs.statSync(itemPath).isDirectory() && item !== 'completed') {
counts[difficulty]++;
}
});
// Count completed problems
const completedPath = path.join(difficultyPath, 'completed');
if (fs.existsSync(completedPath)) {
const completedItems = fs.readdirSync(completedPath);
completedItems.forEach(item => {
const itemPath = path.join(completedPath, item);
if (fs.statSync(itemPath).isDirectory()) {
counts[difficulty]++;
}
});
}
}
});
return counts;
}
// Archive current workspace
function archiveCurrentWork(currentLanguage) {
const projectRoot = process.cwd();
const archiveDir = path.join(projectRoot, `archive-${currentLanguage}`);
// Create archive directory
if (!fs.existsSync(archiveDir)) {
fs.mkdirSync(archiveDir, { recursive: true });
}
// Move difficulty folders to archive
['easy', 'medium', 'hard'].forEach(difficulty => {
const sourcePath = path.join(projectRoot, difficulty);
const targetPath = path.join(archiveDir, difficulty);
if (fs.existsSync(sourcePath)) {
if (fs.existsSync(targetPath)) {
fs.rmSync(targetPath, { recursive: true });
}
fs.renameSync(sourcePath, targetPath);
}
});
console.log(`📦 Archived ${currentLanguage} work to archive-${currentLanguage}/`);
}
// Create fresh workspace structure
function createFreshWorkspace() {
const projectRoot = process.cwd();
['easy', 'medium', 'hard'].forEach(difficulty => {
const difficultyPath = path.join(projectRoot, difficulty);
if (!fs.existsSync(difficultyPath)) {
fs.mkdirSync(difficultyPath, { recursive: true });
}
});
}
// Show current configuration
function showCurrentConfig() {
const config = readConfig();
const counts = countProblems();
const totalProblems = counts.easy + counts.medium + counts.hard;
console.log('🔧 Current Configuration:');
console.log('');
console.log(`📝 Language: ${config.language}`);
console.log(`📊 Problems: ${totalProblems} total (${counts.easy} easy, ${counts.medium} medium, ${counts.hard} hard)`);
console.log(`📅 Created: ${new Date(config.createdAt).toLocaleDateString()}`);
if (config.companies && config.companies.length > 0) {
console.log(`🏢 Company Focus: ${config.companies.join(', ')}`);
}
}
// Switch language
async function switchLanguage(newLanguage) {
if (!LANGUAGE_CONFIGS[newLanguage]) {
console.log(`❌ Unsupported language: ${newLanguage}`);
console.log(`✅ Supported languages: ${Object.keys(LANGUAGE_CONFIGS).join(', ')}`);
return;
}
const currentLanguage = getCurrentLanguage();
if (currentLanguage === newLanguage) {
console.log(`✅ Already using ${newLanguage}`);
return;
}
const counts = countProblems();
const totalProblems = counts.easy + counts.medium + counts.hard;
console.log('⚠️ Language Switch Warning');
console.log(`Current language: ${currentLanguage}`);
console.log(`New language: ${newLanguage}`);
console.log('');
console.log('This will:');
console.log(`❌ Archive all current problems to 'archive-${currentLanguage}/'`);
console.log('🗑️ Clear active workspace');
console.log(`✨ Start fresh with ${newLanguage} environment`);
console.log('');
console.log('📊 Current Progress:');
console.log(` Easy: ${counts.easy} problems`);
console.log(` Medium: ${counts.medium} problems`);
console.log(` Hard: ${counts.hard} problems`);
console.log(` Total: ${totalProblems} problems`);
console.log('');
const confirmed = await askConfirmation('❓ Are you sure you want to switch?');
if (confirmed) {
if (totalProblems > 0) {
archiveCurrentWork(currentLanguage);
}
createFreshWorkspace();
const config = readConfig();
config.language = newLanguage;
config.switchedAt = new Date().toISOString();
if (writeConfig(config)) {
console.log(`🎉 Switched to ${newLanguage}!`);
console.log(`💡 Use 'yarn challenge easy' to start practicing.`);
}
} else {
console.log('❌ Language switch cancelled.');
}
}
// Main function
async function main() {
const args = process.argv.slice(2);
const command = args[0];
if (!command) {
console.log('🔧 LeetCode Language Configuration');
console.log('');
showCurrentConfig();
console.log('');
console.log('💡 Usage:');
console.log(' yarn config # Show current configuration');
console.log(' yarn config javascript # Switch to JavaScript');
console.log(' yarn config python # Switch to Python');
console.log(' yarn config java # Switch to Java');
console.log(' yarn config cpp # Switch to C++');
console.log('');
console.log('✅ Supported Languages:');
Object.keys(LANGUAGE_CONFIGS).forEach(lang => {
const config = LANGUAGE_CONFIGS[lang];
console.log(` ${lang.padEnd(12)} - ${config.extension} files`);
});
return;
}
await switchLanguage(command.toLowerCase());
}
// Export functions for use in other scripts
module.exports = {
getCurrentLanguage,
getLanguageConfig,
LANGUAGE_CONFIGS,
readConfig,
writeConfig
};
// Run if called directly
if (require.main === module) {
main().catch(console.error);
}