ashish-cli
Version:
Universal Code Runner CLI - Execute code in multiple languages without local compilers
214 lines (193 loc) • 5.86 kB
JavaScript
const axios = require("axios");
const chalk = require("chalk");
/**
* Execute code using Piston API (free, no API key required)
*/
async function executeCode(code, language, input = "", options = {}) {
const {
apiEndpoint = "https://emkc.org/api/v2/piston",
timeout = 10,
verbose = false,
} = options;
try {
if (verbose) {
console.log(chalk.blue("Submitting code to Piston API..."));
}
// Map language to Piston format
const pistonLanguage = getPistonLanguage(language);
if (!pistonLanguage) {
throw new Error(
`Language ${language.name} is not supported by Piston API`
);
}
const requestData = {
language: pistonLanguage.name,
version: pistonLanguage.version || "*",
files: [
{
name: getFileName(language),
content: code,
},
],
};
// Add stdin if provided
if (input.trim()) {
requestData.stdin = input;
}
if (verbose) {
console.log(
chalk.blue(
`Language: ${pistonLanguage.name} v${
pistonLanguage.version || "latest"
}`
)
);
}
const response = await axios.post(`${apiEndpoint}/execute`, requestData, {
headers: {
"Content-Type": "application/json",
},
timeout: (timeout + 5) * 1000, // Convert to milliseconds
});
const result = response.data;
// Format result to match expected structure
return {
stdout: result.run?.stdout || "",
stderr: result.run?.stderr || "",
compile_output: result.compile?.stderr || result.compile?.stdout || "",
status: {
id: result.run?.code === 0 ? 3 : 4, // Map to Judge0-like status codes
description: result.run?.code === 0 ? "Accepted" : "Runtime Error",
},
time: null,
memory: null,
exit_code: result.run?.code || 0,
};
} catch (error) {
if (error.response) {
const errorMsg =
error.response.data?.message || error.response.statusText;
throw new Error(
`Piston API Error: ${error.response.status} - ${errorMsg}`
);
} else if (error.request) {
throw new Error(
"Network Error: Unable to reach Piston API. Please check your internet connection."
);
} else {
throw new Error(`Execution Error: ${error.message}`);
}
}
}
/**
* Map our language format to Piston API format
*/
function getPistonLanguage(language) {
const pistonMap = {
C: { name: "c", version: "*" },
"C++": { name: "cpp", version: "*" },
Java: { name: "java", version: "*" },
Python: { name: "python", version: "*" },
JavaScript: { name: "javascript", version: "*" },
TypeScript: { name: "typescript", version: "*" },
"C#": { name: "csharp", version: "*" },
Go: { name: "go", version: "*" },
Rust: { name: "rust", version: "*" },
Ruby: { name: "ruby", version: "*" },
PHP: { name: "php", version: "*" },
Swift: { name: "swift", version: "*" },
Kotlin: { name: "kotlin", version: "*" },
Scala: { name: "scala", version: "*" },
Perl: { name: "perl", version: "*" },
R: { name: "r", version: "*" },
Lua: { name: "lua", version: "*" },
Bash: { name: "bash", version: "*" },
Dart: { name: "dart", version: "*" },
Fortran: { name: "fortran", version: "*" },
Pascal: { name: "pascal", version: "*" },
};
return pistonMap[language.name] || null;
}
/**
* Get appropriate filename for the language
*/
function getFileName(language) {
const fileNames = {
C: "main.c",
"C++": "main.cpp",
Java: "Main.java",
Python: "main.py",
JavaScript: "main.js",
TypeScript: "main.ts",
"C#": "Main.cs",
Go: "main.go",
Rust: "main.rs",
Ruby: "main.rb",
PHP: "main.php",
Swift: "main.swift",
Kotlin: "Main.kt",
Scala: "Main.scala",
Perl: "main.pl",
R: "main.r",
Lua: "main.lua",
Bash: "main.sh",
Dart: "main.dart",
Fortran: "main.f90",
Pascal: "main.pas",
};
return fileNames[language.name] || "main.txt";
}
/**
* Alternative executor using Piston API
*/
async function executeCodeWithPiston(code, language, input = "", options = {}) {
const { apiEndpoint = "https://emkc.org/api/v2/piston", verbose = false } =
options;
try {
if (verbose) {
console.log(chalk.blue("Submitting code to Piston API..."));
}
const requestData = {
language: language.pistonName || language.name.toLowerCase(),
version: language.pistonVersion || "*",
files: [
{
content: code,
},
],
stdin: input,
};
const response = await axios.post(`${apiEndpoint}/execute`, requestData, {
headers: {
"Content-Type": "application/json",
},
});
const result = response.data;
return {
stdout: result.run?.stdout || "",
stderr: result.run?.stderr || "",
compile_output: result.compile?.stderr || "",
status: {
id: result.run?.code === 0 ? 3 : 4, // Map to Judge0 status codes
description: result.run?.code === 0 ? "Accepted" : "Runtime Error",
},
time: null,
memory: null,
};
} catch (error) {
if (error.response) {
throw new Error(
`Piston API Error: ${error.response.status} - ${
error.response.data.message || error.response.statusText
}`
);
} else if (error.request) {
throw new Error("Network Error: Unable to reach Piston API");
} else {
throw new Error(`Execution Error: ${error.message}`);
}
}
}
module.exports = {
executeCode,
};