diff --git a/.changeset/tiny-adults-breathe.md b/.changeset/tiny-adults-breathe.md new file mode 100644 index 00000000..38bb961f --- /dev/null +++ b/.changeset/tiny-adults-breathe.md @@ -0,0 +1,5 @@ +--- +'@e2b/code-interpreter-template': patch +--- + +added typescript support diff --git a/js/tests/defaultKernels.test.ts b/js/tests/defaultKernels.test.ts index 8a7b7f65..5750644a 100644 --- a/js/tests/defaultKernels.test.ts +++ b/js/tests/defaultKernels.test.ts @@ -3,6 +3,23 @@ import { expect } from 'vitest' import { sandboxTest } from './setup' sandboxTest('test js kernel', async ({ sandbox }) => { - const output = await sandbox.runCode('console.log("Hello World!")', { language: 'js' }) + const output = await sandbox.runCode('console.log("Hello World!")', { + language: 'js', + }) expect(output.logs.stdout).toEqual(['Hello World!\n']) }) + +sandboxTest('test ts kernel', async ({ sandbox }) => { + const output = await sandbox.runCode( + 'const message: string = "Hello World!"; console.log(message)', + { language: 'ts' } + ) + expect(output.logs.stdout).toEqual(['Hello World!\n']) +}) + +sandboxTest('test ts kernel errors', async ({ sandbox }) => { + const output = await sandbox.runCode('import x from "module";', { + language: 'typescript', + }) + expect(output.error?.name).toEqual('TypeScriptCompilerError') +}) diff --git a/python/tests/async/test_async_default_kernels.py b/python/tests/async/test_async_default_kernels.py index a632bda6..72153022 100644 --- a/python/tests/async/test_async_default_kernels.py +++ b/python/tests/async/test_async_default_kernels.py @@ -6,3 +6,16 @@ async def test_js_kernel(async_sandbox: AsyncSandbox): "console.log('Hello, World!')", language="js" ) assert execution.logs.stdout == ["Hello, World!\n"] + +async def test_ts_kernel(async_sandbox: AsyncSandbox): + execution = await async_sandbox.run_code( + "const message: string = 'Hello, World!'; console.log(message);", language="ts" + ) + assert execution.logs.stdout == ["Hello, World!\n"] + +async def test_ts_kernel_errors(async_sandbox: AsyncSandbox): + execution = await async_sandbox.run_code( + "import x from 'module';", language="ts" + ) + assert execution.error is not None + assert execution.error.name == "TypeScriptCompilerError" diff --git a/python/tests/sync/test_default_kernels.py b/python/tests/sync/test_default_kernels.py index d0daf820..0695defd 100644 --- a/python/tests/sync/test_default_kernels.py +++ b/python/tests/sync/test_default_kernels.py @@ -18,3 +18,15 @@ def test_r_kernel(sandbox: Sandbox): def test_java_kernel(sandbox: Sandbox): execution = sandbox.run_code('System.out.println("Hello, World!")', language="java") assert execution.logs.stdout[0] == "Hello, World!" + + +@pytest.mark.skip_debug() +def test_ts_kernel(sandbox: Sandbox): + execution = sandbox.run_code("const message: string = 'Hello, World!'; console.log(message)", language="ts") + assert execution.logs.stdout == ["Hello, World!\n"] + + +def test_ts_kernel_errors(sandbox: Sandbox): + execution = sandbox.run_code("import x from 'module';", language="ts") + assert execution.error is not None + assert execution.error.name == "TypeScriptCompilerError" diff --git a/template/.ts.swcrc b/template/.ts.swcrc index da515cd2..cf7cb8d3 100644 --- a/template/.ts.swcrc +++ b/template/.ts.swcrc @@ -12,4 +12,4 @@ "targets": "node 20" }, "isModule": false -} \ No newline at end of file +} diff --git a/template/server/contexts.py b/template/server/contexts.py index 3af317d3..d078dc6e 100644 --- a/template/server/contexts.py +++ b/template/server/contexts.py @@ -11,6 +11,11 @@ logger = logging.Logger(__name__) +def get_kernel_for_language(language: str) -> str: + if language == "typescript": + return "javascript" + + return language def normalize_language(language: Optional[str]) -> str: if not language: @@ -21,13 +26,16 @@ def normalize_language(language: Optional[str]) -> str: if language == "js": return "javascript" + if language == "ts": + return "typescript" + return language async def create_context(client, websockets: dict, language: str, cwd: str) -> Context: data = { "path": str(uuid.uuid4()), - "kernel": {"name": language}, + "kernel": {"name": get_kernel_for_language(language)}, "type": "notebook", "name": str(uuid.uuid4()), } diff --git a/template/server/messaging.py b/template/server/messaging.py index 4f537aa8..d2894d92 100644 --- a/template/server/messaging.py +++ b/template/server/messaging.py @@ -3,6 +3,7 @@ import logging import uuid import asyncio +import subprocess from asyncio import Queue from envs import get_envs @@ -27,7 +28,6 @@ logger = logging.getLogger(__name__) - class Execution: def __init__(self, in_background: bool = False): self.queue = Queue[ @@ -199,6 +199,32 @@ async def execute( + code ) + if self.language == "typescript": + logger.info("Compiling TypeScript: %s", code) + + # call SWC to compile the typescript code + try: + compile_result = subprocess.run("swc --config-file .ts.swcrc --filename index.ts".split(), input=code.encode(), capture_output=True) + + if compile_result.returncode != 0: + logger.error("Error during TypeScript compilation: %s", compile_result.stderr.decode()) + yield Error( + name="TypeScriptCompilerError", + value=compile_result.stderr.decode(), + traceback="", + ) + return + + code = compile_result.stdout.decode() + except Exception as e: + logger.error("Error starting SWC process: %s", e) + yield Error( + name="TypeScriptCompilerError", + value=str(e), + traceback="", + ) + return + logger.info(code) request = self._get_execute_request(message_id, code, False)