Skip to content

Added TypeScript support to the code interpreter #91

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 2, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions js/tests/defaultKernels.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ sandboxTest('test js kernel', async ({ sandbox }) => {
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'])
})
6 changes: 6 additions & 0 deletions python/tests/async/test_async_default_kernels.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ 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"]
6 changes: 6 additions & 0 deletions python/tests/sync/test_default_kernels.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,9 @@ 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"]
15 changes: 15 additions & 0 deletions template/.ts.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "https://swc.rs/schema.json",
"jsc": {
"parser": {
"syntax": "typescript"
}
},
"module": {
"type": "commonjs"
},
"env": {
"targets": "node 20"
},
"isModule": false
}
11 changes: 9 additions & 2 deletions template/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
FROM python:3.10.14

RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-install-recommends \
build-essential curl git util-linux jq sudo nodejs npm fonts-noto-cjk
build-essential curl git util-linux jq sudo fonts-noto-cjk

# Install Node.js 20.x from NodeSource
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
apt-get install -y nodejs

ENV PIP_DEFAULT_TIMEOUT=100 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
Expand All @@ -24,10 +28,13 @@ RUN R -e "install.packages('IRkernel', repos='https://cloud.r-project.org')"
RUN R -e "IRkernel::installspec(user = FALSE, name = 'r', displayname = 'R')"

# Javascript Kernel
RUN npm install -g node-gyp
RUN npm install -g --unsafe-perm ijavascript
RUN ijsinstall --install=global

## TypeScript support
RUN npm install -g @swc/cli @swc/core
COPY .ts.swcrc /root/.ts.swcrc

# Deno Kernel
COPY --from=denoland/deno:bin-2.0.4 /deno /usr/bin/deno
RUN chmod +x /usr/bin/deno
Expand Down
10 changes: 9 additions & 1 deletion template/server/contexts.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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()),
}
Expand Down
19 changes: 19 additions & 0 deletions template/server/messaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging
import uuid
import asyncio
import subprocess

from asyncio import Queue
from envs import get_envs
Expand All @@ -27,6 +28,7 @@

logger = logging.getLogger(__name__)

compile_typescript_cmd = "/usr/lib/node_modules/@swc/cli/bin/swc.js --config-file /root/.ts.swcrc --filename index.ts"

class Execution:
def __init__(self, in_background: bool = False):
Expand Down Expand Up @@ -199,6 +201,23 @@ async def execute(
+ code
)

if self.language == "typescript":
logger.info("Compiling TypeScript: %s", code)

# call swc to compile the typescript code
compile_result = subprocess.run(compile_typescript_cmd.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()

logger.info(code)
request = self._get_execute_request(message_id, code, False)

Expand Down
11 changes: 9 additions & 2 deletions template/test.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ COPY --from=eclipse-temurin:11-jdk $JAVA_HOME $JAVA_HOME
ENV PATH="${JAVA_HOME}/bin:${PATH}"

RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y --no-install-recommends \
build-essential curl git util-linux jq sudo nodejs npm fonts-noto-cjk
build-essential curl git util-linux jq sudo fonts-noto-cjk

# Install Node.js 20.x from NodeSource
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
apt-get install -y nodejs

ENV PIP_DEFAULT_TIMEOUT=100 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
Expand All @@ -19,10 +23,13 @@ COPY ./template/requirements.txt requirements.txt
RUN pip install --no-cache-dir -r requirements.txt && ipython kernel install --name "python3" --user

# Javascript Kernel
RUN npm install -g node-gyp
RUN npm install -g --unsafe-perm ijavascript
RUN ijsinstall --install=global

## TypeScript support
RUN npm install -g @swc/cli @swc/core
COPY ./template/.ts.swcrc /root/.ts.swcrc

# Deno Kernel
COPY --from=denoland/deno:bin-2.0.4 /deno /usr/bin/deno
RUN chmod +x /usr/bin/deno
Expand Down
Loading