Skip to content

Commit 54d8a61

Browse files
authored
Merge pull request #170 from ut-code/copilot/refactor-js-runtime-tests
Extract JS runtime eval logic into `packages/jsEval` workspace with tests
2 parents 781eac1 + 459a5e5 commit 54d8a61

File tree

11 files changed

+333
-91
lines changed

11 files changed

+333
-91
lines changed

.github/workflows/node.js.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,17 @@ jobs:
3232
cache: 'npm'
3333
- run: npm ci
3434
- run: npm run tsc
35+
36+
test-js-eval:
37+
runs-on: ubuntu-latest
38+
strategy:
39+
matrix:
40+
node-version: [22.x]
41+
steps:
42+
- uses: actions/checkout@v4
43+
- uses: actions/setup-node@v4
44+
with:
45+
node-version: ${{ matrix.node-version }}
46+
cache: 'npm'
47+
- run: npm ci
48+
- run: npm test --workspace=packages/jsEval

app/terminal/worker/jsEval.worker.ts

Lines changed: 1 addition & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { expose } from "comlink";
44
import type { ReplOutput } from "../repl";
55
import type { WorkerCapabilities } from "./runtime";
66
import inspect from "object-inspect";
7+
import { replLikeEval, checkSyntax } from "@my-code/js-eval";
78

89
function format(...args: unknown[]): string {
910
// TODO: console.logの第1引数はフォーマット指定文字列を取ることができる
@@ -34,41 +35,6 @@ async function init(/*_interruptBuffer?: Uint8Array*/): Promise<{
3435
return { capabilities: { interrupt: "restart" } };
3536
}
3637

37-
async function replLikeEval(code: string): Promise<unknown> {
38-
// eval()の中でconst,letを使って変数を作成した場合、
39-
// 次に実行するコマンドはスコープ外扱いでありアクセスできなくなってしまうので、
40-
// varに置き換えている
41-
if (code.trim().startsWith("const ")) {
42-
code = "var " + code.trim().slice(6);
43-
} else if (code.trim().startsWith("let ")) {
44-
code = "var " + code.trim().slice(4);
45-
}
46-
// eval()の中でclassを作成した場合も同様
47-
const classRegExp = /^\s*class\s+(\w+)/;
48-
if (classRegExp.test(code)) {
49-
code = code.replace(classRegExp, "var $1 = class $1");
50-
}
51-
52-
if (code.trim().startsWith("{") && code.trim().endsWith("}")) {
53-
// オブジェクトは ( ) で囲わなければならない
54-
try {
55-
return self.eval(`(${code})`);
56-
} catch (e) {
57-
if (e instanceof SyntaxError) {
58-
// オブジェクトではなくブロックだった場合、再度普通に実行
59-
return self.eval(code);
60-
} else {
61-
throw e;
62-
}
63-
}
64-
} else if (/^\s*await\W/.test(code)) {
65-
// promiseをawaitする場合は、promiseの部分だけをevalし、それを外からawaitする
66-
return await self.eval(code.trim().slice(5));
67-
} else {
68-
return self.eval(code);
69-
}
70-
}
71-
7238
async function runCode(
7339
code: string,
7440
onOutput: (output: ReplOutput) => void
@@ -129,32 +95,6 @@ function runFile(
12995
return { updatedFiles: {} as Record<string, string> };
13096
}
13197

132-
async function checkSyntax(
133-
code: string
134-
): Promise<{ status: "complete" | "incomplete" | "invalid" }> {
135-
try {
136-
// Try to create a Function to check syntax
137-
// new Function(code); // <- not working
138-
self.eval(`() => {${code}}`);
139-
return { status: "complete" };
140-
} catch (e) {
141-
// Check if it's a syntax error or if more input is expected
142-
if (e instanceof SyntaxError) {
143-
// Simple heuristic: check for "Unexpected end of input"
144-
if (
145-
e.message.includes("Unexpected token '}'") ||
146-
e.message.includes("Unexpected end of input")
147-
) {
148-
return { status: "incomplete" };
149-
} else {
150-
return { status: "invalid" };
151-
}
152-
} else {
153-
return { status: "invalid" };
154-
}
155-
}
156-
}
157-
15898
async function restoreState(commands: string[]): Promise<object> {
15999
// Re-execute all previously successful commands to restore state
160100
for (const command of commands) {

package-lock.json

Lines changed: 19 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
"version": "0.1.0",
44
"private": true,
55
"type": "module",
6+
"workspaces": [
7+
"packages/*"
8+
],
69
"scripts": {
710
"dev": "npm run cf-typegen && npm run generateLanguages && npm run generateSections && npm run copyAllDTSFiles && npm run removeHinting && next dev",
811
"build": "npm run cf-typegen && npm run generateLanguages && npm run generateSections && npm run copyAllDTSFiles && npm run removeHinting && next build",

packages/jsEval/package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "@my-code/js-eval",
3+
"version": "0.1.0",
4+
"private": true,
5+
"type": "module",
6+
"exports": {
7+
".": "./src/index.ts"
8+
},
9+
"scripts": {
10+
"test": "node --import tsx/esm --test tests/*"
11+
},
12+
"devDependencies": {
13+
"tsx": "^4",
14+
"typescript": "^5"
15+
}
16+
}

0 commit comments

Comments
 (0)