Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
14 changes: 14 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,17 @@ jobs:
cache: 'npm'
- run: npm ci
- run: npm run tsc

test-js-eval:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.x]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm test --workspace=packages/jsEval
62 changes: 1 addition & 61 deletions app/terminal/worker/jsEval.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { expose } from "comlink";
import type { ReplOutput } from "../repl";
import type { WorkerCapabilities } from "./runtime";
import inspect from "object-inspect";
import { replLikeEval, checkSyntax } from "@my-code/js-eval";

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

async function replLikeEval(code: string): Promise<unknown> {
// eval()の中でconst,letを使って変数を作成した場合、
// 次に実行するコマンドはスコープ外扱いでありアクセスできなくなってしまうので、
// varに置き換えている
if (code.trim().startsWith("const ")) {
code = "var " + code.trim().slice(6);
} else if (code.trim().startsWith("let ")) {
code = "var " + code.trim().slice(4);
}
// eval()の中でclassを作成した場合も同様
const classRegExp = /^\s*class\s+(\w+)/;
if (classRegExp.test(code)) {
code = code.replace(classRegExp, "var $1 = class $1");
}

if (code.trim().startsWith("{") && code.trim().endsWith("}")) {
// オブジェクトは ( ) で囲わなければならない
try {
return self.eval(`(${code})`);
} catch (e) {
if (e instanceof SyntaxError) {
// オブジェクトではなくブロックだった場合、再度普通に実行
return self.eval(code);
} else {
throw e;
}
}
} else if (/^\s*await\W/.test(code)) {
// promiseをawaitする場合は、promiseの部分だけをevalし、それを外からawaitする
return await self.eval(code.trim().slice(5));
} else {
return self.eval(code);
}
}

async function runCode(
code: string,
onOutput: (output: ReplOutput) => void
Expand Down Expand Up @@ -129,32 +95,6 @@ function runFile(
return { updatedFiles: {} as Record<string, string> };
}

async function checkSyntax(
code: string
): Promise<{ status: "complete" | "incomplete" | "invalid" }> {
try {
// Try to create a Function to check syntax
// new Function(code); // <- not working
self.eval(`() => {${code}}`);
return { status: "complete" };
} catch (e) {
// Check if it's a syntax error or if more input is expected
if (e instanceof SyntaxError) {
// Simple heuristic: check for "Unexpected end of input"
if (
e.message.includes("Unexpected token '}'") ||
e.message.includes("Unexpected end of input")
) {
return { status: "incomplete" };
} else {
return { status: "invalid" };
}
} else {
return { status: "invalid" };
}
}
}

async function restoreState(commands: string[]): Promise<object> {
// Re-execute all previously successful commands to restore state
for (const command of commands) {
Expand Down
49 changes: 19 additions & 30 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"version": "0.1.0",
"private": true,
"type": "module",
"workspaces": [
"packages/*"
],
"scripts": {
"dev": "npm run cf-typegen && npm run generateLanguages && npm run generateSections && npm run copyAllDTSFiles && npm run removeHinting && next dev",
"build": "npm run cf-typegen && npm run generateLanguages && npm run generateSections && npm run copyAllDTSFiles && npm run removeHinting && next build",
Expand Down
16 changes: 16 additions & 0 deletions packages/jsEval/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "@my-code/js-eval",
"version": "0.1.0",
"private": true,
"type": "module",
"exports": {
".": "./src/index.ts"
},
"scripts": {
"test": "node --import tsx/esm --test tests/*"
},
"devDependencies": {
"tsx": "^4",
"typescript": "^5"
}
}
Loading