@mirascript/cli 0.1.62-alpha.9 → 0.1.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -0
- package/dist/index.js +147 -17
- package/dist/index.js.map +3 -3
- package/package.json +21 -8
- package/src/commands/repl.ts +9 -0
- package/src/commands/run.ts +21 -7
- package/src/index.ts +1 -0
- package/src/utils/color.ts +2 -0
- package/src/utils/execute.ts +9 -4
- package/src/utils/print.ts +1 -3
- package/src/utils/repl.ts +122 -0
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# @mirascript/cli
|
|
2
|
+
|
|
3
|
+
`@mirascript/cli` 是 MiraScript 的命令行工具,提供脚本执行和代码格式化能力,对外暴露 `mirascript` 可执行命令。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add -D @mirascript/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
或直接在工作区中调用:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm --filter @mirascript/cli build
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 命令概览
|
|
18
|
+
|
|
19
|
+
### 运行脚本
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
mirascript run examples/01_hello_world.mira
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
支持的常用选项:
|
|
26
|
+
|
|
27
|
+
- `-e, --eval <script>`:直接执行内联脚本
|
|
28
|
+
- `-t, --template`:以模板模式执行
|
|
29
|
+
- `-v, --variable <key=value>`:注入全局变量,可重复使用
|
|
30
|
+
- `--timeout <ms>`:设置执行超时,`0` 表示不限制
|
|
31
|
+
|
|
32
|
+
示例:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
mirascript run -e "1 + 2"
|
|
36
|
+
mirascript run --template template.miratpl
|
|
37
|
+
mirascript run -v name=world examples/11_interpolation.mira
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 格式化脚本
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
mirascript format examples/**/*.mira
|
|
44
|
+
mirascript format --write examples/**/*.mira
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
支持从标准输入读取:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
cat script.mira | mirascript format -
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 开发
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pnpm --filter @mirascript/cli build
|
|
57
|
+
pnpm --filter @mirascript/cli watch
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
该包依赖 `@mirascript/mirascript` 与 `@mirascript/bindings`,因此本地开发前应先完成工作区依赖安装。
|
package/dist/index.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { program as
|
|
2
|
+
import { program as program4 } from "@commander-js/extra-typings";
|
|
3
3
|
import pkg from "#package.json" with { type: "json" };
|
|
4
4
|
|
|
5
5
|
// src/commands/run.ts
|
|
6
6
|
import { readFile, stat } from "node:fs/promises";
|
|
7
7
|
import { pathToFileURL } from "node:url";
|
|
8
|
+
import { text } from "node:stream/consumers";
|
|
8
9
|
import { InvalidArgumentError, program } from "@commander-js/extra-typings";
|
|
9
10
|
import { compileSync, configCheckpoint } from "@mirascript/mirascript";
|
|
10
11
|
|
|
11
12
|
// src/utils/execute.ts
|
|
12
13
|
import styles2 from "ansi-styles";
|
|
13
14
|
import supportsColor2 from "supports-color";
|
|
14
|
-
import { compile, createVmContext } from "@mirascript/mirascript";
|
|
15
|
+
import { compile, CompileError, createVmContext } from "@mirascript/mirascript";
|
|
15
16
|
import { lib } from "@mirascript/mirascript/subtle";
|
|
16
17
|
|
|
17
18
|
// src/utils/print.ts
|
|
18
19
|
import styles from "ansi-styles";
|
|
19
|
-
import supportsColor from "supports-color";
|
|
20
20
|
import {
|
|
21
21
|
serialize,
|
|
22
22
|
serializeNumber,
|
|
@@ -24,7 +24,12 @@ import {
|
|
|
24
24
|
serializeNil,
|
|
25
25
|
operations
|
|
26
26
|
} from "@mirascript/mirascript/subtle";
|
|
27
|
+
|
|
28
|
+
// src/utils/color.ts
|
|
29
|
+
import supportsColor from "supports-color";
|
|
27
30
|
var noColor = !supportsColor.stdout;
|
|
31
|
+
|
|
32
|
+
// src/utils/print.ts
|
|
28
33
|
var options = {
|
|
29
34
|
maxDepth: 3,
|
|
30
35
|
serializeNil: noColor ? void 0 : () => styles.gray.open + serializeNil() + styles.gray.close,
|
|
@@ -76,16 +81,124 @@ async function execute(script, template, variables, fileName) {
|
|
|
76
81
|
console.log(print(r));
|
|
77
82
|
}
|
|
78
83
|
} catch (ex) {
|
|
79
|
-
|
|
84
|
+
let message;
|
|
85
|
+
if (ex instanceof CompileError) {
|
|
86
|
+
message = ex.message;
|
|
87
|
+
} else {
|
|
88
|
+
message = ex.stack ?? ex.message ?? String(ex);
|
|
89
|
+
}
|
|
80
90
|
if (supportsColor2.stderr) {
|
|
81
|
-
console.error(styles2.red.open +
|
|
91
|
+
console.error(styles2.red.open + message + styles2.red.close);
|
|
82
92
|
} else {
|
|
83
|
-
console.error(
|
|
93
|
+
console.error(message);
|
|
84
94
|
}
|
|
85
95
|
process.exitCode = 2;
|
|
86
96
|
}
|
|
87
97
|
}
|
|
88
98
|
|
|
99
|
+
// src/utils/repl.ts
|
|
100
|
+
import { start, Recoverable } from "node:repl";
|
|
101
|
+
import { homedir } from "node:os";
|
|
102
|
+
import path from "node:path";
|
|
103
|
+
import { callbackify } from "node:util";
|
|
104
|
+
import { once } from "node:events";
|
|
105
|
+
import { isNativeError } from "node:util/types";
|
|
106
|
+
import {
|
|
107
|
+
compile as compile2,
|
|
108
|
+
CompileError as CompileError2,
|
|
109
|
+
createVmContext as createVmContext2
|
|
110
|
+
} from "@mirascript/mirascript";
|
|
111
|
+
import { DiagnosticCode, constants } from "@mirascript/mirascript/subtle";
|
|
112
|
+
function throwRecoverableError(error) {
|
|
113
|
+
if (!(error instanceof CompileError2)) throw error;
|
|
114
|
+
if (error.message.includes(DiagnosticCode[DiagnosticCode.MissingCloseBrace]) || error.message.includes(DiagnosticCode[DiagnosticCode.MissingCloseBracket]) || error.message.includes(DiagnosticCode[DiagnosticCode.MissingCloseParen]) || error.message.includes(DiagnosticCode[DiagnosticCode.UnterminatedInterpolation]) || error.message.includes(DiagnosticCode[DiagnosticCode.ExpressionExpected]) || error.message.includes(DiagnosticCode[DiagnosticCode.PatternExpected]) || error.message.includes(DiagnosticCode[DiagnosticCode.UnterminatedString]) || error.message.includes(DiagnosticCode[DiagnosticCode.MissingSemicolon])) {
|
|
115
|
+
throw new Recoverable(error);
|
|
116
|
+
}
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
var REG_BINDING = new RegExp(
|
|
120
|
+
String.raw`^\s*(?:const|let|let\s+mut)\s+(${constants.REG_IDENTIFIER.source})\s*=\s*`,
|
|
121
|
+
"u"
|
|
122
|
+
);
|
|
123
|
+
var REG_MODULE = new RegExp(String.raw`^\s*mod\s+(${constants.REG_IDENTIFIER.source})\s*\{`, "u");
|
|
124
|
+
async function startRepl() {
|
|
125
|
+
let lastResult = null;
|
|
126
|
+
const context = /* @__PURE__ */ new Map();
|
|
127
|
+
const vmContext = createVmContext2(
|
|
128
|
+
(key) => {
|
|
129
|
+
if (context.has(key)) {
|
|
130
|
+
return context.get(key);
|
|
131
|
+
}
|
|
132
|
+
if (key === "$") {
|
|
133
|
+
return lastResult;
|
|
134
|
+
}
|
|
135
|
+
return void 0;
|
|
136
|
+
},
|
|
137
|
+
() => {
|
|
138
|
+
const keys = [...context.keys()];
|
|
139
|
+
keys.push("$");
|
|
140
|
+
return keys;
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
const evaluator = async (cmd, fileName) => {
|
|
144
|
+
const opt = { input_mode: "Script", fileName, pretty: true, sourceMap: true };
|
|
145
|
+
try {
|
|
146
|
+
const code = cmd.replaceAll(/[\r\n]/g, "\n");
|
|
147
|
+
const bind = REG_BINDING.exec(code);
|
|
148
|
+
if (bind) {
|
|
149
|
+
const varName = bind[1];
|
|
150
|
+
const script2 = await compile2(`${code};return ${varName};`, opt);
|
|
151
|
+
const result2 = script2(vmContext);
|
|
152
|
+
context.set(varName, result2);
|
|
153
|
+
return result2;
|
|
154
|
+
}
|
|
155
|
+
const mod = REG_MODULE.exec(code);
|
|
156
|
+
if (mod) {
|
|
157
|
+
const modName = mod[1];
|
|
158
|
+
const script2 = await compile2(`${code};return ${modName};`, opt);
|
|
159
|
+
const result2 = script2(vmContext);
|
|
160
|
+
context.set(modName, result2);
|
|
161
|
+
return result2;
|
|
162
|
+
}
|
|
163
|
+
const script = await compile2(code, opt);
|
|
164
|
+
const result = script(vmContext);
|
|
165
|
+
lastResult = result;
|
|
166
|
+
return result;
|
|
167
|
+
} catch (err) {
|
|
168
|
+
throwRecoverableError(err);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
const repl = start({
|
|
172
|
+
useColors: !noColor,
|
|
173
|
+
useGlobal: false,
|
|
174
|
+
eval: callbackify(async (cmd, _, fileName) => evaluator(cmd, fileName)),
|
|
175
|
+
completer: (line) => {
|
|
176
|
+
const lastToken = line.split(/[\s.]+/).pop() ?? "";
|
|
177
|
+
return [vmContext.keys().filter((k) => k.startsWith(lastToken)), lastToken];
|
|
178
|
+
},
|
|
179
|
+
writer: (value) => {
|
|
180
|
+
if (value === void 0) {
|
|
181
|
+
return "";
|
|
182
|
+
}
|
|
183
|
+
if (isNativeError(value)) {
|
|
184
|
+
return `${value.name}: ${value.message}`;
|
|
185
|
+
}
|
|
186
|
+
return print(value);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
repl.setupHistory({
|
|
190
|
+
filePath: path.resolve(homedir(), ".mirascript_repl_history"),
|
|
191
|
+
removeHistoryDuplicates: true,
|
|
192
|
+
onHistoryFileLoaded: (err) => {
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
repl.on("reset", () => {
|
|
196
|
+
context.clear();
|
|
197
|
+
lastResult = null;
|
|
198
|
+
});
|
|
199
|
+
await once(repl, "exit");
|
|
200
|
+
}
|
|
201
|
+
|
|
89
202
|
// src/commands/run.ts
|
|
90
203
|
var DEFAULT_TIMEOUT = 3e3;
|
|
91
204
|
program.command("run", { isDefault: true }).description("执行 MiraScript 脚本,默认命令").option(
|
|
@@ -120,14 +233,26 @@ program.command("run", { isDefault: true }).description("执行 MiraScript 脚
|
|
|
120
233
|
return ms;
|
|
121
234
|
},
|
|
122
235
|
DEFAULT_TIMEOUT
|
|
123
|
-
).option("--no-template", "使用脚本模式").option("-e, --eval <script>", "要执行的脚本").argument("[script]", "
|
|
236
|
+
).option("--no-template", "使用脚本模式").option("-e, --eval <script>", "要执行的脚本").argument("[script]", "要执行的脚本文件路径,使用 - 从标准输入读取(如果提供了 -e 则忽略此参数)").action(async (script, opt) => {
|
|
237
|
+
if (opt.eval == null && script == null) {
|
|
238
|
+
await startRepl();
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
124
241
|
configCheckpoint(opt.timeout || Number.POSITIVE_INFINITY);
|
|
125
242
|
if (opt.eval != null) {
|
|
126
|
-
const
|
|
127
|
-
await execute(opt.eval,
|
|
243
|
+
const template2 = !!opt.template;
|
|
244
|
+
await execute(opt.eval, template2, opt.variable, template2 ? "eval.miratpl" : "eval.mira");
|
|
128
245
|
return;
|
|
129
246
|
}
|
|
130
|
-
|
|
247
|
+
let codeStr;
|
|
248
|
+
let template;
|
|
249
|
+
let url;
|
|
250
|
+
script ??= "-";
|
|
251
|
+
if (script === "-") {
|
|
252
|
+
codeStr = await text(process.stdin);
|
|
253
|
+
template = !!opt.template;
|
|
254
|
+
url = "stdin";
|
|
255
|
+
} else {
|
|
131
256
|
try {
|
|
132
257
|
const s = await stat(script);
|
|
133
258
|
if (!s.isFile()) {
|
|
@@ -148,12 +273,11 @@ program.command("run", { isDefault: true }).description("执行 MiraScript 脚
|
|
|
148
273
|
}
|
|
149
274
|
return;
|
|
150
275
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return;
|
|
276
|
+
codeStr = await readFile(script, "utf8");
|
|
277
|
+
template = opt.template ?? script.endsWith(".miratpl");
|
|
278
|
+
url = pathToFileURL(script).href;
|
|
155
279
|
}
|
|
156
|
-
|
|
280
|
+
await execute(codeStr, template, opt.variable, url);
|
|
157
281
|
});
|
|
158
282
|
|
|
159
283
|
// src/commands/format.ts
|
|
@@ -235,11 +359,17 @@ command.description("格式化 MiraScript 脚本").option("-w, --write", "直接
|
|
|
235
359
|
}
|
|
236
360
|
});
|
|
237
361
|
|
|
362
|
+
// src/commands/repl.ts
|
|
363
|
+
import { program as program3 } from "@commander-js/extra-typings";
|
|
364
|
+
program3.command("repl").description("启动 MiraScript REPL(交互式命令行)").action(async () => {
|
|
365
|
+
await startRepl();
|
|
366
|
+
});
|
|
367
|
+
|
|
238
368
|
// src/index.ts
|
|
239
|
-
var p =
|
|
369
|
+
var p = program4;
|
|
240
370
|
var binName = Object.keys(pkg.bin)[0];
|
|
241
371
|
if (binName) {
|
|
242
|
-
p =
|
|
372
|
+
p = program4.name(binName);
|
|
243
373
|
}
|
|
244
374
|
var index_default = p.version(pkg.version).description(pkg.description);
|
|
245
375
|
export {
|
package/dist/index.js.map
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts", "../src/commands/run.ts", "../src/utils/execute.ts", "../src/utils/print.ts", "../src/commands/format.ts"],
|
|
4
|
-
"mappings": ";AAAA,SAAS,WAAAA,gBAAe;AACxB,OAAO,SAAS,gBAAgB,KAAK,EAAE,MAAM,OAAO;;;ACDpD,SAAS,UAAU,YAAY;AAC/B,SAAS,qBAAqB;AAC9B,SAAS,sBAAsB,eAAe;AAC9C,SAAS,aAAa,wBAAsC;;;
|
|
5
|
-
"names": ["program", "styles", "supportsColor", "options", "format", "supportsColor", "styles", "p", "program", "program"]
|
|
3
|
+
"sources": ["../src/index.ts", "../src/commands/run.ts", "../src/utils/execute.ts", "../src/utils/print.ts", "../src/utils/color.ts", "../src/utils/repl.ts", "../src/commands/format.ts", "../src/commands/repl.ts"],
|
|
4
|
+
"mappings": "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",
|
|
5
|
+
"names": ["program", "styles", "supportsColor", "options", "format", "supportsColor", "styles", "compile", "CompileError", "createVmContext", "CompileError", "createVmContext", "script", "compile", "result", "p", "template", "program", "program", "program", "program"]
|
|
6
6
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mirascript/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.64",
|
|
4
4
|
"author": "CloudPSS",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Cli for MiraScript, an expression based scripting language.",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"mirascript",
|
|
9
|
+
"cli",
|
|
10
|
+
"formatter",
|
|
11
|
+
"runner",
|
|
12
|
+
"script"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://mira.cloudpss.net",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/CloudPSS/MiraScript.git",
|
|
18
|
+
"directory": "packages/cli"
|
|
19
|
+
},
|
|
7
20
|
"type": "module",
|
|
8
21
|
"main": "./dist/index.js",
|
|
9
22
|
"bin": {
|
|
@@ -21,20 +34,20 @@
|
|
|
21
34
|
"#package.json": "./package.json"
|
|
22
35
|
},
|
|
23
36
|
"dependencies": {
|
|
24
|
-
"@commander-js/extra-typings": "^
|
|
37
|
+
"@commander-js/extra-typings": "^15.0.0",
|
|
25
38
|
"ansi-styles": "^6.2.3",
|
|
26
|
-
"commander": "^
|
|
39
|
+
"commander": "^15.0.0",
|
|
27
40
|
"supports-color": "^10.2.2",
|
|
28
|
-
"@mirascript/bindings": "~0.1.
|
|
29
|
-
"@mirascript/mirascript": "~0.1.
|
|
41
|
+
"@mirascript/bindings": "~0.1.64",
|
|
42
|
+
"@mirascript/mirascript": "~0.1.64"
|
|
30
43
|
},
|
|
31
44
|
"devDependencies": {
|
|
32
|
-
"@types/node": "^
|
|
33
|
-
"type-fest": "^5.
|
|
45
|
+
"@types/node": "^26.0.1",
|
|
46
|
+
"type-fest": "^5.7.0"
|
|
34
47
|
},
|
|
35
48
|
"scripts": {
|
|
36
49
|
"watch": "pnpm build --watch",
|
|
37
|
-
"build": "pnpm clean && node ./esbuild.config.js",
|
|
50
|
+
"build": "pnpm clean && pnpm tsc && node ./esbuild.config.js",
|
|
38
51
|
"clean": "rimraf dist"
|
|
39
52
|
}
|
|
40
53
|
}
|
package/src/commands/run.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { readFile, stat } from 'node:fs/promises';
|
|
2
2
|
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { text } from 'node:stream/consumers';
|
|
3
4
|
import { InvalidArgumentError, program } from '@commander-js/extra-typings';
|
|
4
5
|
import { compileSync, configCheckpoint, type VmValue } from '@mirascript/mirascript';
|
|
5
6
|
import { execute } from '../utils/execute.js';
|
|
7
|
+
import { startRepl } from '../utils/repl.js';
|
|
6
8
|
|
|
7
9
|
const DEFAULT_TIMEOUT = 3000;
|
|
8
10
|
|
|
@@ -47,15 +49,27 @@ program
|
|
|
47
49
|
)
|
|
48
50
|
.option('--no-template', '使用脚本模式')
|
|
49
51
|
.option('-e, --eval <script>', '要执行的脚本')
|
|
50
|
-
.argument('[script]', '
|
|
52
|
+
.argument('[script]', '要执行的脚本文件路径,使用 - 从标准输入读取(如果提供了 -e 则忽略此参数)')
|
|
51
53
|
.action(async (script, opt) => {
|
|
54
|
+
if (opt.eval == null && script == null) {
|
|
55
|
+
await startRepl();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
52
58
|
configCheckpoint(opt.timeout || Number.POSITIVE_INFINITY);
|
|
53
59
|
if (opt.eval != null) {
|
|
54
60
|
const template = !!opt.template;
|
|
55
61
|
await execute(opt.eval, template, opt.variable, template ? 'eval.miratpl' : 'eval.mira');
|
|
56
62
|
return;
|
|
57
63
|
}
|
|
58
|
-
|
|
64
|
+
let codeStr: string;
|
|
65
|
+
let template: boolean;
|
|
66
|
+
let url: string;
|
|
67
|
+
script ??= '-';
|
|
68
|
+
if (script === '-') {
|
|
69
|
+
codeStr = await text(process.stdin);
|
|
70
|
+
template = !!opt.template;
|
|
71
|
+
url = 'stdin';
|
|
72
|
+
} else {
|
|
59
73
|
try {
|
|
60
74
|
const s = await stat(script);
|
|
61
75
|
if (!s.isFile()) {
|
|
@@ -76,10 +90,10 @@ program
|
|
|
76
90
|
}
|
|
77
91
|
return;
|
|
78
92
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
93
|
+
|
|
94
|
+
codeStr = await readFile(script, 'utf8');
|
|
95
|
+
template = opt.template ?? script.endsWith('.miratpl');
|
|
96
|
+
url = pathToFileURL(script).href;
|
|
83
97
|
}
|
|
84
|
-
|
|
98
|
+
await execute(codeStr, template, opt.variable, url);
|
|
85
99
|
});
|
package/src/index.ts
CHANGED
package/src/utils/execute.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import styles from 'ansi-styles';
|
|
3
3
|
import supportsColor from 'supports-color';
|
|
4
|
-
import { compile, createVmContext, type VmValue } from '@mirascript/mirascript';
|
|
4
|
+
import { compile, CompileError, createVmContext, type VmValue } from '@mirascript/mirascript';
|
|
5
5
|
import { lib } from '@mirascript/mirascript/subtle';
|
|
6
6
|
import { print } from './print.js';
|
|
7
7
|
|
|
@@ -33,11 +33,16 @@ export async function execute(
|
|
|
33
33
|
console.log(print(r));
|
|
34
34
|
}
|
|
35
35
|
} catch (ex) {
|
|
36
|
-
|
|
36
|
+
let message: string | undefined;
|
|
37
|
+
if (ex instanceof CompileError) {
|
|
38
|
+
message = ex.message;
|
|
39
|
+
} else {
|
|
40
|
+
message = (ex as Error).stack ?? (ex as Error).message ?? String(ex);
|
|
41
|
+
}
|
|
37
42
|
if (supportsColor.stderr) {
|
|
38
|
-
console.error(styles.red.open +
|
|
43
|
+
console.error(styles.red.open + message + styles.red.close);
|
|
39
44
|
} else {
|
|
40
|
-
console.error(
|
|
45
|
+
console.error(message);
|
|
41
46
|
}
|
|
42
47
|
process.exitCode = 2;
|
|
43
48
|
}
|
package/src/utils/print.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import styles from 'ansi-styles';
|
|
2
|
-
import supportsColor from 'supports-color';
|
|
3
2
|
import type { VmAny, VmRecord } from '@mirascript/mirascript';
|
|
4
3
|
import {
|
|
5
4
|
serialize,
|
|
@@ -9,8 +8,7 @@ import {
|
|
|
9
8
|
type SerializeOptions,
|
|
10
9
|
operations,
|
|
11
10
|
} from '@mirascript/mirascript/subtle';
|
|
12
|
-
|
|
13
|
-
const noColor = !supportsColor.stdout;
|
|
11
|
+
import { noColor } from './color.js';
|
|
14
12
|
|
|
15
13
|
const options: Partial<SerializeOptions> = {
|
|
16
14
|
maxDepth: 3,
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { start, Recoverable } from 'node:repl';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { callbackify } from 'node:util';
|
|
5
|
+
import { once } from 'node:events';
|
|
6
|
+
import { isNativeError } from 'node:util/types';
|
|
7
|
+
import {
|
|
8
|
+
compile,
|
|
9
|
+
CompileError,
|
|
10
|
+
createVmContext,
|
|
11
|
+
type TranspileOptions,
|
|
12
|
+
type VmAny,
|
|
13
|
+
type VmValue,
|
|
14
|
+
} from '@mirascript/mirascript';
|
|
15
|
+
import { DiagnosticCode, constants } from '@mirascript/mirascript/subtle';
|
|
16
|
+
import { print } from './print.js';
|
|
17
|
+
import { noColor } from './color.js';
|
|
18
|
+
|
|
19
|
+
/** 检查错误 */
|
|
20
|
+
function throwRecoverableError(error: unknown): never {
|
|
21
|
+
if (!(error instanceof CompileError)) throw error;
|
|
22
|
+
if (
|
|
23
|
+
error.message.includes(DiagnosticCode[DiagnosticCode.MissingCloseBrace]) ||
|
|
24
|
+
error.message.includes(DiagnosticCode[DiagnosticCode.MissingCloseBracket]) ||
|
|
25
|
+
error.message.includes(DiagnosticCode[DiagnosticCode.MissingCloseParen]) ||
|
|
26
|
+
error.message.includes(DiagnosticCode[DiagnosticCode.UnterminatedInterpolation]) ||
|
|
27
|
+
error.message.includes(DiagnosticCode[DiagnosticCode.ExpressionExpected]) ||
|
|
28
|
+
error.message.includes(DiagnosticCode[DiagnosticCode.PatternExpected]) ||
|
|
29
|
+
error.message.includes(DiagnosticCode[DiagnosticCode.UnterminatedString]) ||
|
|
30
|
+
error.message.includes(DiagnosticCode[DiagnosticCode.MissingSemicolon])
|
|
31
|
+
) {
|
|
32
|
+
throw new Recoverable(error);
|
|
33
|
+
}
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const REG_BINDING = new RegExp(
|
|
38
|
+
String.raw`^\s*(?:const|let|let\s+mut)\s+(${constants.REG_IDENTIFIER.source})\s*=\s*`,
|
|
39
|
+
'u',
|
|
40
|
+
);
|
|
41
|
+
const REG_MODULE = new RegExp(String.raw`^\s*mod\s+(${constants.REG_IDENTIFIER.source})\s*\{`, 'u');
|
|
42
|
+
|
|
43
|
+
/** 启动 REPL */
|
|
44
|
+
export async function startRepl(): Promise<void> {
|
|
45
|
+
let lastResult: VmValue = null;
|
|
46
|
+
const context = new Map<string, VmValue>();
|
|
47
|
+
const vmContext = createVmContext(
|
|
48
|
+
(key) => {
|
|
49
|
+
if (context.has(key)) {
|
|
50
|
+
return context.get(key)!;
|
|
51
|
+
}
|
|
52
|
+
if (key === '$') {
|
|
53
|
+
return lastResult;
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
},
|
|
57
|
+
() => {
|
|
58
|
+
const keys = [...context.keys()];
|
|
59
|
+
keys.push('$');
|
|
60
|
+
return keys;
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
const evaluator = async (cmd: string, fileName: string): Promise<VmAny> => {
|
|
64
|
+
const opt: TranspileOptions = { input_mode: 'Script', fileName, pretty: true, sourceMap: true };
|
|
65
|
+
try {
|
|
66
|
+
const code = cmd.replaceAll(/[\r\n]/g, '\n');
|
|
67
|
+
const bind = REG_BINDING.exec(code);
|
|
68
|
+
if (bind) {
|
|
69
|
+
const varName = bind[1]!;
|
|
70
|
+
const script = await compile(`${code};return ${varName};`, opt);
|
|
71
|
+
const result = script(vmContext);
|
|
72
|
+
context.set(varName, result);
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
const mod = REG_MODULE.exec(code);
|
|
76
|
+
if (mod) {
|
|
77
|
+
const modName = mod[1]!;
|
|
78
|
+
const script = await compile(`${code};return ${modName};`, opt);
|
|
79
|
+
const result = script(vmContext);
|
|
80
|
+
context.set(modName, result);
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const script = await compile(code, opt);
|
|
85
|
+
const result = script(vmContext);
|
|
86
|
+
lastResult = result;
|
|
87
|
+
return result;
|
|
88
|
+
} catch (err) {
|
|
89
|
+
throwRecoverableError(err);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const repl = start({
|
|
93
|
+
useColors: !noColor,
|
|
94
|
+
useGlobal: false,
|
|
95
|
+
eval: callbackify(async (cmd: string, _: unknown, fileName: string) => evaluator(cmd, fileName)),
|
|
96
|
+
completer: (line: string) => {
|
|
97
|
+
const lastToken = line.split(/[\s.]+/).pop() ?? '';
|
|
98
|
+
return [vmContext.keys().filter((k) => k.startsWith(lastToken)), lastToken];
|
|
99
|
+
},
|
|
100
|
+
writer: (value: VmAny | Error) => {
|
|
101
|
+
if (value === undefined) {
|
|
102
|
+
return '';
|
|
103
|
+
}
|
|
104
|
+
if (isNativeError(value)) {
|
|
105
|
+
return `${value.name}: ${value.message}`;
|
|
106
|
+
}
|
|
107
|
+
return print(value);
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
repl.setupHistory({
|
|
111
|
+
filePath: path.resolve(homedir(), '.mirascript_repl_history'),
|
|
112
|
+
removeHistoryDuplicates: true,
|
|
113
|
+
onHistoryFileLoaded: (err) => {
|
|
114
|
+
// Ignore error if history file does not exist
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
repl.on('reset', () => {
|
|
118
|
+
context.clear();
|
|
119
|
+
lastResult = null;
|
|
120
|
+
});
|
|
121
|
+
await once(repl, 'exit');
|
|
122
|
+
}
|