Skip to content

Commit 9894d70

Browse files
committed
ファイル分割
1 parent 8af7d3b commit 9894d70

7 files changed

Lines changed: 160 additions & 189 deletions

File tree

package-lock.json

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

packages/jsEval/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
".": "./src/index.ts"
88
},
99
"scripts": {
10-
"test": "node --import tsx/esm --test src/index.test.ts"
10+
"test": "node --import tsx/esm --test tests/*"
1111
},
1212
"devDependencies": {
13-
"tsx": "*",
14-
"typescript": "*"
13+
"tsx": "^4",
14+
"typescript": "^5"
1515
}
1616
}

packages/jsEval/src/eval.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Use indirect eval so that var declarations go to the global scope,
2+
// matching the behaviour of a REPL where variables persist across calls.
3+
// Security note: eval is intentionally used here to implement a JavaScript
4+
// REPL. This package must only be loaded in an isolated context (e.g. a Web
5+
// Worker or a sandboxed Node.js process) where arbitrary code execution is
6+
// the expected behaviour.
7+
// @ts-expect-error comma operator for indirect eval
8+
const indirectEval: (code: string) => unknown = (0, eval);
9+
10+
export async function replLikeEval(code: string): Promise<unknown> {
11+
// eval()の中でconst,letを使って変数を作成した場合、
12+
// 次に実行するコマンドはスコープ外扱いでありアクセスできなくなってしまうので、
13+
// varに置き換えている
14+
if (code.trim().startsWith("const ")) {
15+
code = "var " + code.trim().slice(6);
16+
} else if (code.trim().startsWith("let ")) {
17+
code = "var " + code.trim().slice(4);
18+
}
19+
// eval()の中でclassを作成した場合も同様
20+
const classRegExp = /^\s*class\s+(\w+)/;
21+
if (classRegExp.test(code)) {
22+
code = code.replace(classRegExp, "var $1 = class $1");
23+
}
24+
25+
if (code.trim().startsWith("{") && code.trim().endsWith("}")) {
26+
// オブジェクトは ( ) で囲わなければならない
27+
try {
28+
return indirectEval(`(${code})`);
29+
} catch (e) {
30+
if (e instanceof SyntaxError) {
31+
// オブジェクトではなくブロックだった場合、再度普通に実行
32+
return indirectEval(code);
33+
} else {
34+
throw e;
35+
}
36+
}
37+
} else if (/^\s*await\W/.test(code)) {
38+
// promiseをawaitする場合は、promiseの部分だけをevalし、それを外からawaitする
39+
return await (indirectEval(code.trim().slice(5)) as Promise<unknown>);
40+
} else {
41+
return indirectEval(code);
42+
}
43+
}

packages/jsEval/src/index.ts

Lines changed: 2 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,2 @@
1-
// Use indirect eval so that var declarations go to the global scope,
2-
// matching the behaviour of a REPL where variables persist across calls.
3-
// Security note: eval is intentionally used here to implement a JavaScript
4-
// REPL. This package must only be loaded in an isolated context (e.g. a Web
5-
// Worker or a sandboxed Node.js process) where arbitrary code execution is
6-
// the expected behaviour.
7-
// eslint-disable-next-line no-eval
8-
const indirectEval: (code: string) => unknown = (0, eval);
9-
10-
export async function replLikeEval(code: string): Promise<unknown> {
11-
// eval()の中でconst,letを使って変数を作成した場合、
12-
// 次に実行するコマンドはスコープ外扱いでありアクセスできなくなってしまうので、
13-
// varに置き換えている
14-
if (code.trim().startsWith("const ")) {
15-
code = "var " + code.trim().slice(6);
16-
} else if (code.trim().startsWith("let ")) {
17-
code = "var " + code.trim().slice(4);
18-
}
19-
// eval()の中でclassを作成した場合も同様
20-
const classRegExp = /^\s*class\s+(\w+)/;
21-
if (classRegExp.test(code)) {
22-
code = code.replace(classRegExp, "var $1 = class $1");
23-
}
24-
25-
if (code.trim().startsWith("{") && code.trim().endsWith("}")) {
26-
// オブジェクトは ( ) で囲わなければならない
27-
try {
28-
return indirectEval(`(${code})`);
29-
} catch (e) {
30-
if (e instanceof SyntaxError) {
31-
// オブジェクトではなくブロックだった場合、再度普通に実行
32-
return indirectEval(code);
33-
} else {
34-
throw e;
35-
}
36-
}
37-
} else if (/^\s*await\W/.test(code)) {
38-
// promiseをawaitする場合は、promiseの部分だけをevalし、それを外からawaitする
39-
return await (indirectEval(code.trim().slice(5)) as Promise<unknown>);
40-
} else {
41-
return indirectEval(code);
42-
}
43-
}
44-
45-
export async function checkSyntax(
46-
code: string
47-
): Promise<{ status: "complete" | "incomplete" | "invalid" }> {
48-
try {
49-
indirectEval(`() => {${code}}`);
50-
return { status: "complete" };
51-
} catch (e) {
52-
if (e instanceof SyntaxError) {
53-
if (
54-
e.message.includes("Unexpected token '}'") ||
55-
e.message.includes("Unexpected end of input")
56-
) {
57-
return { status: "incomplete" };
58-
} else {
59-
return { status: "invalid" };
60-
}
61-
} else {
62-
return { status: "invalid" };
63-
}
64-
}
65-
}
1+
export { replLikeEval } from "./eval.js";
2+
export { checkSyntax } from "./syntax.js";

packages/jsEval/src/syntax.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// @ts-expect-error comma operator for indirect eval
2+
const indirectEval: (code: string) => unknown = (0, eval);
3+
4+
export async function checkSyntax(
5+
code: string
6+
): Promise<{ status: "complete" | "incomplete" | "invalid" }> {
7+
try {
8+
indirectEval(`() => {${code}}`);
9+
return { status: "complete" };
10+
} catch (e) {
11+
if (e instanceof SyntaxError) {
12+
if (
13+
e.message.includes("Unexpected token '}'") ||
14+
e.message.includes("Unexpected end of input")
15+
) {
16+
return { status: "incomplete" };
17+
} else {
18+
return { status: "invalid" };
19+
}
20+
} else {
21+
return { status: "invalid" };
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)