@mirascript/mirascript 0.1.92 → 0.1.93
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/dist/chunk-7JTZW66P.js +1075 -0
- package/dist/chunk-7JTZW66P.js.map +6 -0
- package/dist/{chunk-Y7S6AHE7.js → chunk-F3FHURMG.js} +55 -939
- package/dist/chunk-F3FHURMG.js.map +6 -0
- package/dist/{chunk-HHKY7Y7L.js → chunk-GTNLLZL4.js} +4 -82
- package/dist/chunk-GTNLLZL4.js.map +6 -0
- package/dist/chunk-H2OHULLB.js +89 -0
- package/dist/chunk-H2OHULLB.js.map +6 -0
- package/dist/compiler/worker.js +2 -1
- package/dist/compiler/worker.js.map +1 -1
- package/dist/experimental-context.d.ts +93 -0
- package/dist/experimental-context.d.ts.map +1 -0
- package/dist/experimental-context.js +90 -0
- package/dist/experimental-context.js.map +6 -0
- package/dist/helpers/convert/string.d.ts +0 -2
- package/dist/helpers/convert/string.d.ts.map +1 -1
- package/dist/helpers/error.d.ts.map +1 -1
- package/dist/helpers/serialize/display.d.ts +29 -0
- package/dist/helpers/serialize/display.d.ts.map +1 -0
- package/dist/helpers/serialize/index.d.ts +5 -0
- package/dist/helpers/serialize/index.d.ts.map +1 -0
- package/dist/helpers/serialize/interface.d.ts +33 -0
- package/dist/helpers/serialize/interface.d.ts.map +1 -0
- package/dist/helpers/serialize/serialize.d.ts +39 -0
- package/dist/helpers/serialize/serialize.d.ts.map +1 -0
- package/dist/helpers/serialize/simple.d.ts +9 -0
- package/dist/helpers/serialize/simple.d.ts.map +1 -0
- package/dist/helpers/serialize/string.d.ts +6 -0
- package/dist/helpers/serialize/string.d.ts.map +1 -0
- package/dist/helpers/utils.d.ts +4 -0
- package/dist/helpers/utils.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -8
- package/dist/index.js.map +1 -1
- package/dist/subtle.d.ts +1 -1
- package/dist/subtle.d.ts.map +1 -1
- package/dist/subtle.js +9 -6
- package/dist/subtle.js.map +1 -1
- package/dist/vm/effects/run.d.ts +7 -0
- package/dist/vm/effects/run.d.ts.map +1 -0
- package/dist/vm/effects/state.d.ts +62 -0
- package/dist/vm/effects/state.d.ts.map +1 -0
- package/dist/vm/effects/wrap.d.ts +4 -0
- package/dist/vm/effects/wrap.d.ts.map +1 -0
- package/dist/vm/lib/global/bit.d.ts +7 -7
- package/dist/vm/lib/global/bit.d.ts.map +1 -1
- package/dist/vm/lib/global/debug.d.ts +1 -1
- package/dist/vm/lib/global/debug.d.ts.map +1 -1
- package/dist/vm/lib/global/json.d.ts +2 -2
- package/dist/vm/lib/global/json.d.ts.map +1 -1
- package/dist/vm/lib/global/math/index.d.ts +2 -2
- package/dist/vm/lib/global/math/index.d.ts.map +1 -1
- package/dist/vm/lib/global/math/tgamma.d.ts +2 -2
- package/dist/vm/lib/global/math/tgamma.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/all-any.d.ts +2 -2
- package/dist/vm/lib/global/sequence/all-any.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/entries.d.ts +3 -3
- package/dist/vm/lib/global/sequence/entries.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/find.d.ts +1 -1
- package/dist/vm/lib/global/sequence/flatten.d.ts +1 -1
- package/dist/vm/lib/global/sequence/flatten.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/fold.d.ts +1 -1
- package/dist/vm/lib/global/sequence/fold.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/group.d.ts +1 -1
- package/dist/vm/lib/global/sequence/group.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/len.d.ts +1 -1
- package/dist/vm/lib/global/sequence/len.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/map-filter.d.ts +3 -3
- package/dist/vm/lib/global/sequence/map-filter.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/new.d.ts +2 -2
- package/dist/vm/lib/global/sequence/new.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/repeat.d.ts +1 -1
- package/dist/vm/lib/global/sequence/repeat.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/reverse.d.ts +1 -1
- package/dist/vm/lib/global/sequence/reverse.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/sort.d.ts +2 -2
- package/dist/vm/lib/global/sequence/sort.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/unique.d.ts +2 -2
- package/dist/vm/lib/global/sequence/unique.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/with.d.ts +1 -1
- package/dist/vm/lib/global/sequence/with.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/zip.d.ts +1 -1
- package/dist/vm/lib/global/sequence/zip.d.ts.map +1 -1
- package/dist/vm/lib/global/string/case.d.ts +2 -2
- package/dist/vm/lib/global/string/case.d.ts.map +1 -1
- package/dist/vm/lib/global/string/index.d.ts +4 -4
- package/dist/vm/lib/global/string/index.d.ts.map +1 -1
- package/dist/vm/lib/global/string/search.d.ts +3 -3
- package/dist/vm/lib/global/string/search.d.ts.map +1 -1
- package/dist/vm/lib/global/string/trim.d.ts +3 -3
- package/dist/vm/lib/global/string/trim.d.ts.map +1 -1
- package/dist/vm/lib/global/time.d.ts +3 -3
- package/dist/vm/lib/global/time.d.ts.map +1 -1
- package/dist/vm/lib/global/to-primitive.d.ts +3 -3
- package/dist/vm/lib/global/to-primitive.d.ts.map +1 -1
- package/dist/vm/lib/mod/matrix/bin-ops.d.ts +6 -6
- package/dist/vm/lib/mod/matrix/bin-ops.d.ts.map +1 -1
- package/dist/vm/lib/mod/matrix/fill.d.ts +4 -4
- package/dist/vm/lib/mod/matrix/fill.d.ts.map +1 -1
- package/dist/vm/lib/mod/matrix/invert.d.ts +1 -1
- package/dist/vm/lib/mod/matrix/invert.d.ts.map +1 -1
- package/dist/vm/lib/mod/matrix/size.d.ts +1 -1
- package/dist/vm/lib/mod/matrix/size.d.ts.map +1 -1
- package/dist/vm/lib/mod/matrix/transpose.d.ts +1 -1
- package/dist/vm/lib/mod/matrix/transpose.d.ts.map +1 -1
- package/dist/vm/types/function.d.ts +4 -2
- package/dist/vm/types/function.d.ts.map +1 -1
- package/package.json +8 -4
- package/src/experimental-context.ts +121 -0
- package/src/helpers/convert/boolean.ts +1 -1
- package/src/helpers/convert/number.ts +1 -1
- package/src/helpers/convert/string.ts +6 -11
- package/src/helpers/error.ts +2 -0
- package/src/helpers/serialize/display.ts +60 -0
- package/src/helpers/serialize/index.ts +4 -0
- package/src/helpers/serialize/interface.ts +33 -0
- package/src/helpers/serialize/serialize.ts +200 -0
- package/src/helpers/serialize/simple.ts +25 -0
- package/src/helpers/serialize/string.ts +91 -0
- package/src/helpers/utils.ts +11 -2
- package/src/index.ts +1 -1
- package/src/subtle.ts +2 -2
- package/src/vm/effects/run.ts +80 -0
- package/src/vm/effects/state.ts +108 -0
- package/src/vm/effects/wrap.ts +71 -0
- package/src/vm/lib/global/debug.ts +6 -3
- package/src/vm/lib/global/math/index.ts +9 -5
- package/src/vm/lib/global/sequence/zip.ts +1 -1
- package/src/vm/lib/global/time.ts +5 -2
- package/src/vm/lib/helpers.ts +1 -1
- package/src/vm/operations/call.ts +1 -1
- package/src/vm/operations/compound.ts +1 -1
- package/src/vm/operations/iterable.ts +1 -1
- package/src/vm/operations/slice.ts +1 -1
- package/src/vm/operations/spread.ts +1 -1
- package/src/vm/types/function.ts +7 -5
- package/dist/chunk-HHKY7Y7L.js.map +0 -6
- package/dist/chunk-Y7S6AHE7.js.map +0 -6
- package/dist/helpers/serialize.d.ts +0 -63
- package/dist/helpers/serialize.d.ts.map +0 -1
- package/src/helpers/serialize.ts +0 -397
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { VmFunction, type VmFunctionLike, type VmFunctionOptionLike } from './vm/types/function.js';
|
|
2
|
+
import { wrapEffect } from './vm/effects/wrap.js';
|
|
3
|
+
import type { VmValue } from './vm/types/index.js';
|
|
4
|
+
import { defineProperty } from './helpers/utils.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* ## 实验性执行上下文
|
|
8
|
+
* JS backend 可通过 `experimental-context` 显式启用可挂起的 Host Function。
|
|
9
|
+
* 生成的脚本仍是同步函数,运行时在异步操作完成后从入口重新执行,并复用已记录的 effect。
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { compileSync, createVmContext, VmFunction } from '@mirascript/mirascript';
|
|
13
|
+
* import { runInContext } from '@mirascript/mirascript/experimental-context';
|
|
14
|
+
*
|
|
15
|
+
* const globals = createVmContext({
|
|
16
|
+
* load: VmFunction.async(
|
|
17
|
+
* async (id) => {
|
|
18
|
+
* if (typeof id !== 'string') throw new TypeError('id must be a string');
|
|
19
|
+
* // Host 实现显式转换外部结果,返回合法 VM 值。
|
|
20
|
+
* return { id, value: 42 };
|
|
21
|
+
* },
|
|
22
|
+
* { name: 'load', summary: '加载数据' },
|
|
23
|
+
* ),
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* runInContext(
|
|
27
|
+
* compileSync('load("example").value'),
|
|
28
|
+
* globals,
|
|
29
|
+
* (value) => console.log(value),
|
|
30
|
+
* (error) => console.error(error),
|
|
31
|
+
* );
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* 实际导入实验入口后,现有 `VmFunction` 对象获得以下方法;也可使用
|
|
35
|
+
* `import '@mirascript/mirascript/experimental-context'` 仅安装扩展。
|
|
36
|
+
* `import type` 不会安装运行时方法。模块声明增强在包含该入口的整个 TypeScript 编译项目中生效。
|
|
37
|
+
*
|
|
38
|
+
* | 方法 | 用途 | 在执行上下文中的行 * 为 |
|
|
39
|
+
* | ------------------------------- | ----------------------------- | * ------------------------------------------------ |
|
|
40
|
+
* | `VmFunction.memo(fn, option?)` | 随机数、时间、外部状态读取 | 每个逻辑调用缓存结果或异 * 常 |
|
|
41
|
+
* | `VmFunction.once(fn, option?)` | 输出等立即发生的副作用 | 每个逻辑调用只执行一次,缓存结果或异 * 常,不回滚 |
|
|
42
|
+
* | `VmFunction.async(fn, option?)` | 返回 PromiseLike 的 Host 操作 | 启动一次,等待完成,在原逻辑调用处返 * 回结果或抛错 |
|
|
43
|
+
*
|
|
44
|
+
* 三个方法都直接返回已包装的 `VmFunction`,`option` 与普通构造器一致。
|
|
45
|
+
* 输入参数遵循 `VmFunctionLike`,包含缺省参数的 `undefined`;返回值或异步完成值必须为
|
|
46
|
+
* `VmAny | void`。三个方法均为泛型函数,像普通 `VmFunction` 一样保留输入函数的类型;
|
|
47
|
+
* `async` 保留参数与 `this` 类型,将 PromiseLike 的完成值作为同步返回值。
|
|
48
|
+
* 包装器不转换普通 JS 对象,调用方自行检查或断言 VM 参数与脚本结果。
|
|
49
|
+
*
|
|
50
|
+
* `runInContext(script, globals, onDone, onError)` 接受 `VmScript` 和
|
|
51
|
+
* `VmContext | null | undefined`,返回 `void`。结果固定为 `VmValue`,错误为 `unknown`。
|
|
52
|
+
* 无挂起时,完成或错误回调在当前调用栈中执行;挂起后,通过微任务恢复执行。
|
|
53
|
+
* 回调只通知一次,并在退出执行上下文后调用。回调自身抛错不会转交另一个回调;
|
|
54
|
+
* 同步时直接传播,异步时作为微任务异常抛出。
|
|
55
|
+
*
|
|
56
|
+
* 普通 `script(globals)` 保持同步,不创建 effect journal。
|
|
57
|
+
* `memo/once` 在上下文外直接执行,`async` 则在启动 Host 实现之前抛出 `AsyncRequiredError`。
|
|
58
|
+
* 实验入口同时导出 `ReplayMismatchError` 和 `ContextReentrancyError`。
|
|
59
|
+
*
|
|
60
|
+
* 内置 `random`、时间转换函数未传日期或传入 `nil` 时的当前时间读取,以及
|
|
61
|
+
* `debug_print`、`panic` 的输出部分已接入 effect 管理。日志沿用原有异步输出时序,
|
|
62
|
+
* 完成回调不等待日志输出。Checkpoint 超时仅约束每轮同步执行,不包括异步等待。
|
|
63
|
+
*
|
|
64
|
+
* ### Replay 条件与限制
|
|
65
|
+
*
|
|
66
|
+
* - 包装函数应在执行入口之外创建,确保每次 replay 使用相同的函数身份。
|
|
67
|
+
* - 缓存按调用顺序记录,不按参数去重;循环中的同一函数可有多个独立逻辑调用。
|
|
68
|
+
* - 未包装的函数、globals 查询和外部对象读取必须满足 replay 条件。运行时不快照 globals、
|
|
69
|
+
* 拦截 getter 或外部对象写入,也不管理未声明的副作用。
|
|
70
|
+
* - 结果按引用缓存,不拷贝或冻结。不要在运行期间修改缓存对象或影响控制流的外部状态。
|
|
71
|
+
* - 函数身份或调用序列长度变化会报错,但不会比较参数,不能检测所有 replay 分歧。
|
|
72
|
+
* - 支持独立执行交错等待;拒绝执行中的嵌套 `runInContext`,以及被管理 Host 实现同步调用
|
|
73
|
+
* 其他 effect。Host 实现在 `await` 后回调脚本执行 effect 不受支持。
|
|
74
|
+
* - 不要捕获并吞掉运行时控制信号后继续产生副作用。已记录的挂起或致命契约错误不会因此消失。
|
|
75
|
+
* - 不提供取消、事务、deferred commit 或跨安装副本的 context 互操作;Rust/Python backend 不变。
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 异步 Mirascript 函数签名
|
|
80
|
+
* @see {@link VmFunctionLike}
|
|
81
|
+
*/
|
|
82
|
+
type VmAsyncFunctionLike = (
|
|
83
|
+
this: void,
|
|
84
|
+
...args: ReadonlyArray<VmValue | undefined>
|
|
85
|
+
) => PromiseLike<ReturnType<VmFunctionLike>> | ReturnType<VmFunctionLike>;
|
|
86
|
+
|
|
87
|
+
/** 保留异步函数的参数类型,将完成值作为同步返回值 */
|
|
88
|
+
type ResumedFunction<T extends VmAsyncFunctionLike> = T extends (...args: infer A extends readonly unknown[]) => unknown
|
|
89
|
+
? (this: void, ...args: A) => Awaited<ReturnType<T>>
|
|
90
|
+
: never;
|
|
91
|
+
|
|
92
|
+
declare module './vm/types/function.js' {
|
|
93
|
+
namespace VmFunction {
|
|
94
|
+
/** 创建读取函数,每次逻辑调用缓存返回值或异常 */
|
|
95
|
+
function memo<T extends VmFunctionLike>(fn: T, option?: VmFunctionOptionLike<T>): VmFunction<T>;
|
|
96
|
+
/** 创建副作用函数,每次逻辑调用最多执行一次,不支持回滚 */
|
|
97
|
+
function once<T extends VmFunctionLike>(fn: T, option?: VmFunctionOptionLike<T>): VmFunction<T>;
|
|
98
|
+
/** 创建可挂起的异步函数,需要通过 runInContext 执行 */
|
|
99
|
+
function async<T extends VmAsyncFunctionLike>(
|
|
100
|
+
fn: T,
|
|
101
|
+
option?: VmFunctionOptionLike<ResumedFunction<T>>,
|
|
102
|
+
): VmFunction<ResumedFunction<T>>;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** 创建 effect 函数,已标记的 Mirascript 函数也需要重新包装 */
|
|
107
|
+
function createEffectWrapper(kind: 'memo' | 'once' | 'async') {
|
|
108
|
+
return (fn: VmFunctionLike | VmAsyncFunctionLike, option?: VmFunctionOptionLike) => {
|
|
109
|
+
if (typeof fn != 'function') throw new TypeError('Invalid function');
|
|
110
|
+
const wrapped = wrapEffect<ReadonlyArray<VmValue | undefined>, ReturnType<VmFunctionLike>>(kind, fn);
|
|
111
|
+
defineProperty(wrapped, 'name', { value: fn.name, configurable: true });
|
|
112
|
+
return VmFunction(wrapped, option);
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
defineProperty(VmFunction, 'memo', { value: createEffectWrapper('memo') });
|
|
117
|
+
defineProperty(VmFunction, 'once', { value: createEffectWrapper('once') });
|
|
118
|
+
defineProperty(VmFunction, 'async', { value: createEffectWrapper('async') });
|
|
119
|
+
|
|
120
|
+
export { runInContext } from './vm/effects/run.js';
|
|
121
|
+
export { AsyncRequiredError, ReplayMismatchError, ContextReentrancyError } from './vm/effects/state.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { VmAny } from '../../vm/index.js';
|
|
2
2
|
import { VmError } from '../error.js';
|
|
3
|
-
import { display } from '../serialize.js';
|
|
3
|
+
import { display } from '../serialize/display.js';
|
|
4
4
|
|
|
5
5
|
/** 转换为 boolean */
|
|
6
6
|
export function toBoolean<F = undefined>(value: VmAny, fallback?: F): boolean | Exclude<F, undefined> {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { VmAny } from '../../vm/index.js';
|
|
2
2
|
import { VmError } from '../error.js';
|
|
3
|
-
import { display } from '../serialize.js';
|
|
3
|
+
import { display } from '../serialize/display.js';
|
|
4
4
|
import { NegativeInfinity, NotNumber, PositiveInfinity } from '../utils.js';
|
|
5
5
|
|
|
6
6
|
const parseInt = (value: string, radix: number): number => Number.parseInt(value.slice(2), radix);
|
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import type { VmAny, VmRecord } from '../../vm/index.js';
|
|
2
|
+
import { rethrowControl } from '../../vm/effects/state.js';
|
|
2
3
|
import { isVmArray, isVmWrapper } from '../types/index.js';
|
|
3
4
|
import { VmError } from '../error.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export function numberToString(value: number, minusZero: boolean): string {
|
|
9
|
-
if (isNaN(value)) return 'nan';
|
|
10
|
-
if (value === Infinity) return 'inf';
|
|
11
|
-
if (value === -Infinity) return '-inf';
|
|
12
|
-
if (minusZero && value === 0 && 1 / value < 0) return '-0';
|
|
13
|
-
return String(value);
|
|
14
|
-
}
|
|
5
|
+
import { keys } from '../utils.js';
|
|
6
|
+
import { display } from '../serialize/display.js';
|
|
7
|
+
import { numberToString } from '../serialize/simple.js';
|
|
8
|
+
import { displayFunction } from '../serialize/display.js';
|
|
15
9
|
|
|
16
10
|
/** 转换为 string */
|
|
17
11
|
export function innerToString(value: VmAny, useBraces: boolean): string {
|
|
@@ -46,6 +40,7 @@ export function toString<F = undefined>(value: VmAny, fallback?: F): string | Ex
|
|
|
46
40
|
try {
|
|
47
41
|
return innerToString(value, false);
|
|
48
42
|
} catch (ex) {
|
|
43
|
+
rethrowControl(ex);
|
|
49
44
|
if (fallback === undefined) {
|
|
50
45
|
const e = new VmError(`Failed to convert value to string: ${display(value)}`, '');
|
|
51
46
|
e.cause = ex;
|
package/src/helpers/error.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { VmAny } from '../vm/types/index.js';
|
|
2
|
+
import { rethrowControl } from '../vm/effects/state.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* VM 预期的错误
|
|
@@ -16,6 +17,7 @@ export class VmError extends Error {
|
|
|
16
17
|
|
|
17
18
|
/** 从其他错误构造 */
|
|
18
19
|
static from(prefix: string, error: unknown, recovered: VmAny): VmError {
|
|
20
|
+
rethrowControl(error);
|
|
19
21
|
if (prefix) {
|
|
20
22
|
if (prefix.endsWith(':')) {
|
|
21
23
|
prefix += ' ';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { VmAny, VmExtern, VmFunction, VmModule } from '../../vm/index.js';
|
|
2
|
+
import { rethrowControl } from '../../vm/effects/state.js';
|
|
3
|
+
import { getVmFunctionInfo } from '../types/index.js';
|
|
4
|
+
import type { SerializeOptions } from './interface.js';
|
|
5
|
+
import { DEFAULT_OPTIONS, mergeOptions, serializeImpl } from './serialize.js';
|
|
6
|
+
|
|
7
|
+
/** 将 MiraScript 函数转化为 MiraScript 字符串 */
|
|
8
|
+
export function displayFunction(value: VmFunction): string {
|
|
9
|
+
try {
|
|
10
|
+
const name = getVmFunctionInfo(value)?.fullName;
|
|
11
|
+
return name ? `<function ${name}>` : `<function>`;
|
|
12
|
+
/* c8 ignore next 4 */
|
|
13
|
+
} catch (error) {
|
|
14
|
+
rethrowControl(error);
|
|
15
|
+
return `<function>`;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** 将 MiraScript 模块转化为 MiraScript 字符串 */
|
|
20
|
+
export function displayModule(value: VmModule): string {
|
|
21
|
+
try {
|
|
22
|
+
return value.toString(true);
|
|
23
|
+
/* c8 ignore next 4 */
|
|
24
|
+
} catch (error) {
|
|
25
|
+
rethrowControl(error);
|
|
26
|
+
return `<module>`;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** 将 MiraScript 外部值转化为 MiraScript 字符串 */
|
|
31
|
+
export function displayExtern(value: VmExtern): string {
|
|
32
|
+
try {
|
|
33
|
+
const tag = `<extern ${value.tag}>`;
|
|
34
|
+
const rep = value.toString(true);
|
|
35
|
+
if (rep === tag || rep.length > 50) {
|
|
36
|
+
return tag;
|
|
37
|
+
}
|
|
38
|
+
return `${tag} ${rep}`;
|
|
39
|
+
/* c8 ignore next 4 */
|
|
40
|
+
} catch (error) {
|
|
41
|
+
rethrowControl(error);
|
|
42
|
+
return `<extern>`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const DISPLAY_OPTIONS = Object.freeze({
|
|
47
|
+
...DEFAULT_OPTIONS,
|
|
48
|
+
maxDepth: 3,
|
|
49
|
+
serializeFunction: displayFunction,
|
|
50
|
+
serializeModule: displayModule,
|
|
51
|
+
serializeExtern: displayExtern,
|
|
52
|
+
} satisfies SerializeOptions);
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 将 MiraScript 值转化为 MiraScript 字符串。
|
|
56
|
+
*/
|
|
57
|
+
export function display(value: VmAny, options?: Partial<SerializeOptions>): string {
|
|
58
|
+
const opt = mergeOptions(DISPLAY_OPTIONS, options);
|
|
59
|
+
return serializeImpl(value, 0, opt);
|
|
60
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { serializeNil, serializeBoolean, serializeNumber } from './simple.js';
|
|
2
|
+
export type { SerializeOptions } from './interface.js';
|
|
3
|
+
export { serialize, serializeArray, serializeString, serializeRecord, serializeRecordKey } from './serialize.js';
|
|
4
|
+
export { display as serializeForDisplay } from './display.js';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { VmArray, VmExtern, VmFunction, VmModule, VmRecord } from '../../vm/index.js';
|
|
2
|
+
|
|
3
|
+
/** 序列化设置 */
|
|
4
|
+
export interface SerializeOptions {
|
|
5
|
+
/** 最大递归深度,超过该深度的值将被序列化为 `nil`,默认值为 128 */
|
|
6
|
+
maxDepth: number;
|
|
7
|
+
/** 序列化 nil 值 */
|
|
8
|
+
serializeNil: (options: SerializeOptions) => string;
|
|
9
|
+
/** 序列化布尔值 */
|
|
10
|
+
serializeBoolean: (value: boolean, options: SerializeOptions) => string;
|
|
11
|
+
/** 序列化数字 */
|
|
12
|
+
serializeNumber: (value: number, options: SerializeOptions) => string;
|
|
13
|
+
/** 序列化字符串 */
|
|
14
|
+
serializeString: (value: string, options: SerializeOptions) => string;
|
|
15
|
+
/** 序列化字符串引号 */
|
|
16
|
+
serializeStringQuote: (value: string, open: boolean, options: SerializeOptions) => string;
|
|
17
|
+
/** 序列化字符串转义序列 */
|
|
18
|
+
serializeStringEscape: (value: string, options: SerializeOptions) => string;
|
|
19
|
+
/** 序列化字符串常规内容 */
|
|
20
|
+
serializeStringContent: (value: string, options: SerializeOptions) => string;
|
|
21
|
+
/** 序列化数组 */
|
|
22
|
+
serializeArray: (value: VmArray, depth: number, options: SerializeOptions) => string;
|
|
23
|
+
/** 序列化记录 */
|
|
24
|
+
serializeRecord: (value: VmRecord, depth: number, options: SerializeOptions) => string;
|
|
25
|
+
/** 序列化属性名 */
|
|
26
|
+
serializePropName: (value: number | string, options: SerializeOptions) => string;
|
|
27
|
+
/** 序列化函数 */
|
|
28
|
+
serializeFunction: (value: VmFunction, options: SerializeOptions) => string;
|
|
29
|
+
/** 序列化模块 */
|
|
30
|
+
serializeModule: (value: VmModule, depth: number, options: SerializeOptions) => string;
|
|
31
|
+
/** 序列化外部值 */
|
|
32
|
+
serializeExtern: (value: VmExtern, depth: number, options: SerializeOptions) => string;
|
|
33
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { REG_IDENTIFIER_FULL, REG_ORDINAL_FULL } from '@mirascript/constants';
|
|
2
|
+
import type { VmArray, VmAny, VmRecord } from '../../vm/index.js';
|
|
3
|
+
import { entries, hasOwn } from '../utils.js';
|
|
4
|
+
import {
|
|
5
|
+
isVmArray,
|
|
6
|
+
isVmArrayLikeRecordByEntries,
|
|
7
|
+
isVmExtern,
|
|
8
|
+
isVmFunction,
|
|
9
|
+
isVmModule,
|
|
10
|
+
isVmRecord,
|
|
11
|
+
} from '../types/index.js';
|
|
12
|
+
import type { SerializeOptions } from './interface.js';
|
|
13
|
+
import { serializeNil, serializeBoolean, serializeNumber } from './simple.js';
|
|
14
|
+
import { serializeStringImpl } from './string.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 将 MiraScript 字符串序列化为 MiraScript 字面量。
|
|
18
|
+
*/
|
|
19
|
+
export function serializeString(value: string, options?: Partial<SerializeOptions>): string {
|
|
20
|
+
return serializeStringImpl(value, getSerializeOptions(options));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** 使用默认选项序列化属性名 */
|
|
24
|
+
function serializeRecordKeyDefault(key: string): string {
|
|
25
|
+
if (REG_ORDINAL_FULL.test(key) || REG_IDENTIFIER_FULL.test(key)) {
|
|
26
|
+
return key;
|
|
27
|
+
}
|
|
28
|
+
return serializeStringImpl(key, DEFAULT_OPTIONS);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** 序列化属性名 */
|
|
32
|
+
function serializeRecordKeyOpt(value: string, options: Readonly<SerializeOptions>): string {
|
|
33
|
+
if (isDefaultOptions(options)) {
|
|
34
|
+
return serializeRecordKeyDefault(value);
|
|
35
|
+
}
|
|
36
|
+
if (REG_ORDINAL_FULL.test(value)) {
|
|
37
|
+
// 合法的数字属性名
|
|
38
|
+
return options.serializePropName(Number(value), options);
|
|
39
|
+
}
|
|
40
|
+
if (REG_IDENTIFIER_FULL.test(value)) {
|
|
41
|
+
// 合法的标识符
|
|
42
|
+
return options.serializePropName(value, options);
|
|
43
|
+
}
|
|
44
|
+
// 否则,序列化为字符串
|
|
45
|
+
return options.serializeString(value, options);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** 序列化属性名 */
|
|
49
|
+
export function serializeRecordKey(key: string, options?: Partial<SerializeOptions>): string {
|
|
50
|
+
if (isDefaultOptions(options)) {
|
|
51
|
+
return serializeRecordKeyDefault(key);
|
|
52
|
+
}
|
|
53
|
+
return serializeRecordKeyOpt(key, getSerializeOptions(options));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** 序列化数组 */
|
|
57
|
+
export function serializeArray(value: VmArray, depth: number, options: Readonly<SerializeOptions>): string {
|
|
58
|
+
if (depth > options.maxDepth) return `[]`;
|
|
59
|
+
if (value.length === 0) return '[]';
|
|
60
|
+
let result = '[';
|
|
61
|
+
for (let i = 0; i < value.length; i++) {
|
|
62
|
+
if (i > 0) result += ', ';
|
|
63
|
+
result += serializeImpl(value[i], depth, options);
|
|
64
|
+
}
|
|
65
|
+
result += ']';
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
70
|
+
const { valueOf } = Object.prototype;
|
|
71
|
+
/**
|
|
72
|
+
* 如果值有自定义的 valueOf 方法,调用它并返回结果,否则返回 undefined。
|
|
73
|
+
*/
|
|
74
|
+
function customValueOf(value: VmRecord): VmAny | undefined {
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
76
|
+
const thisValueOf = value.valueOf;
|
|
77
|
+
if (typeof thisValueOf !== 'function' || thisValueOf === valueOf) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
const customValue = thisValueOf.call(value) as VmAny | undefined;
|
|
81
|
+
if (customValue === value) return undefined;
|
|
82
|
+
return customValue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** 序列化记录 */
|
|
86
|
+
export function serializeRecord(value: VmRecord, depth: number, options: Readonly<SerializeOptions>): string {
|
|
87
|
+
const customValue = customValueOf(value);
|
|
88
|
+
if (customValue !== undefined) {
|
|
89
|
+
return serializeImpl(customValue, depth - 1, options);
|
|
90
|
+
}
|
|
91
|
+
if (depth > options.maxDepth) return `()`;
|
|
92
|
+
const e = entries(value);
|
|
93
|
+
if (e.length === 0) return '()';
|
|
94
|
+
if (e.length === 1) {
|
|
95
|
+
const [k, v] = e[0]!;
|
|
96
|
+
if (k === '0') {
|
|
97
|
+
return `(${serializeImpl(v, depth, options)},)`; // 单个元素数组
|
|
98
|
+
}
|
|
99
|
+
return `(${serializeRecordKeyOpt(k, options)}: ${serializeImpl(v, depth, options)})`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const omitKey = isVmArrayLikeRecordByEntries(e);
|
|
103
|
+
let result = '(';
|
|
104
|
+
for (const [key, val] of e) {
|
|
105
|
+
if (result.length > 1) result += ', ';
|
|
106
|
+
if (omitKey) {
|
|
107
|
+
result += serializeImpl(val, depth, options);
|
|
108
|
+
} else {
|
|
109
|
+
result += `${serializeRecordKeyOpt(key, options)}: ${serializeImpl(val, depth, options)}`;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
result += ')';
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** 序列化 */
|
|
117
|
+
export function serializeImpl(value: VmAny | undefined, depth: number, options: Readonly<SerializeOptions>): string {
|
|
118
|
+
if (value == null) {
|
|
119
|
+
return options.serializeNil(options);
|
|
120
|
+
}
|
|
121
|
+
if (typeof value == 'boolean') {
|
|
122
|
+
return options.serializeBoolean(value, options);
|
|
123
|
+
}
|
|
124
|
+
if (typeof value == 'number') {
|
|
125
|
+
return options.serializeNumber(value, options);
|
|
126
|
+
}
|
|
127
|
+
if (typeof value == 'string') {
|
|
128
|
+
return options.serializeString(value, options);
|
|
129
|
+
}
|
|
130
|
+
if (isVmFunction(value)) {
|
|
131
|
+
return options.serializeFunction(value, options);
|
|
132
|
+
}
|
|
133
|
+
if (isVmModule(value)) {
|
|
134
|
+
return options.serializeModule(value, depth + 1, options);
|
|
135
|
+
}
|
|
136
|
+
if (isVmExtern(value)) {
|
|
137
|
+
return options.serializeExtern(value, depth + 1, options);
|
|
138
|
+
}
|
|
139
|
+
if (isVmArray(value)) {
|
|
140
|
+
return options.serializeArray(value, depth + 1, options);
|
|
141
|
+
}
|
|
142
|
+
if (isVmRecord(value)) {
|
|
143
|
+
return options.serializeRecord(value, depth + 1, options);
|
|
144
|
+
}
|
|
145
|
+
// 不支持序列化的值
|
|
146
|
+
value satisfies never;
|
|
147
|
+
return options.serializeNil(options);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 将 MiraScript 值序列化为 MiraScript 字面量字符串,非常量值默认转换为 `nil`。
|
|
152
|
+
*/
|
|
153
|
+
export function serialize(value: VmAny, options?: Partial<SerializeOptions>): string {
|
|
154
|
+
return serializeImpl(value, 0, getSerializeOptions(options));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** 是否为默认选项 */
|
|
158
|
+
function isDefaultOptions(options: Partial<SerializeOptions> | undefined): boolean {
|
|
159
|
+
return options == null || options === DEFAULT_OPTIONS;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** 合并选项 */
|
|
163
|
+
export function mergeOptions(
|
|
164
|
+
base: Readonly<SerializeOptions>,
|
|
165
|
+
options: Partial<SerializeOptions> | null | undefined,
|
|
166
|
+
): Readonly<SerializeOptions> {
|
|
167
|
+
if (options == null) return base;
|
|
168
|
+
let opt: SerializeOptions | null = null;
|
|
169
|
+
for (const key in options) {
|
|
170
|
+
if (!hasOwn(options, key) || !hasOwn(base, key)) continue;
|
|
171
|
+
const el = options[key as keyof SerializeOptions];
|
|
172
|
+
if (el == null) continue;
|
|
173
|
+
opt ??= { ...base };
|
|
174
|
+
opt[key as keyof SerializeOptions] = el as never;
|
|
175
|
+
}
|
|
176
|
+
return opt ? Object.freeze(opt) : base;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** 获取选项 */
|
|
180
|
+
function getSerializeOptions(options: Partial<SerializeOptions> | undefined): Readonly<SerializeOptions> {
|
|
181
|
+
if (isDefaultOptions(options)) return DEFAULT_OPTIONS;
|
|
182
|
+
return mergeOptions(DEFAULT_OPTIONS, options);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export const DEFAULT_OPTIONS = Object.freeze({
|
|
186
|
+
maxDepth: 128,
|
|
187
|
+
serializeNil,
|
|
188
|
+
serializeBoolean,
|
|
189
|
+
serializeNumber,
|
|
190
|
+
serializeString: serializeStringImpl,
|
|
191
|
+
serializeStringQuote: (value) => value,
|
|
192
|
+
serializeStringEscape: (value) => value,
|
|
193
|
+
serializeStringContent: (value) => value,
|
|
194
|
+
serializeArray,
|
|
195
|
+
serializeRecord,
|
|
196
|
+
serializePropName: String,
|
|
197
|
+
serializeFunction: serializeNil,
|
|
198
|
+
serializeModule: serializeNil,
|
|
199
|
+
serializeExtern: serializeNil,
|
|
200
|
+
} satisfies SerializeOptions);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { isNaN } from '../utils.js';
|
|
2
|
+
|
|
3
|
+
/** 序列化 nil 值 */
|
|
4
|
+
export function serializeNil(): string {
|
|
5
|
+
return 'nil';
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** 序列化布尔值 */
|
|
9
|
+
export function serializeBoolean(value: boolean): string {
|
|
10
|
+
return value ? 'true' : 'false';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** 转换为 string */
|
|
14
|
+
export function numberToString(value: number, minusZero: boolean): string {
|
|
15
|
+
if (isNaN(value)) return 'nan';
|
|
16
|
+
if (value === Infinity) return 'inf';
|
|
17
|
+
if (value === -Infinity) return '-inf';
|
|
18
|
+
if (minusZero && value === 0 && 1 / value < 0) return '-0';
|
|
19
|
+
return String(value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** 序列化数字 */
|
|
23
|
+
export function serializeNumber(value: number): string {
|
|
24
|
+
return numberToString(value, true);
|
|
25
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { SerializeOptions } from './interface.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 将 MiraScript 转义字符串序列化为 MiraScript 字面量。
|
|
5
|
+
*/
|
|
6
|
+
function serializeStringEscaped(escaped: string, options: Readonly<SerializeOptions>): string {
|
|
7
|
+
return options.serializeStringEscape('\\' + escaped, options);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 将 MiraScript 普通字符串序列化为 MiraScript 字面量。
|
|
12
|
+
*/
|
|
13
|
+
function serializeStringContent(value: string, options: Readonly<SerializeOptions>): string {
|
|
14
|
+
return options.serializeStringContent(value, options);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const STRING_QUOTE = `'`;
|
|
18
|
+
const STRING_REG = new RegExp(String.raw`[${STRING_QUOTE}\\\$\p{C}\u2028\u2029]`, 'gu');
|
|
19
|
+
const STRING_MARK = /^[\p{M}]$/u;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 序列化为特殊字符
|
|
23
|
+
*/
|
|
24
|
+
function serializeSpecialChar(char: string, options: Readonly<SerializeOptions>): string {
|
|
25
|
+
if (char === STRING_QUOTE) {
|
|
26
|
+
return serializeStringEscaped(STRING_QUOTE, options);
|
|
27
|
+
} else if (char === '\0') {
|
|
28
|
+
return serializeStringEscaped(`0`, options);
|
|
29
|
+
} else if (char === '\n') {
|
|
30
|
+
return serializeStringEscaped(`n`, options);
|
|
31
|
+
} else if (char === '\r') {
|
|
32
|
+
return serializeStringEscaped(`r`, options);
|
|
33
|
+
} else if (char === '\t') {
|
|
34
|
+
return serializeStringEscaped(`t`, options);
|
|
35
|
+
} else if (char === '\b') {
|
|
36
|
+
return serializeStringEscaped(`b`, options);
|
|
37
|
+
} else if (char === '\f') {
|
|
38
|
+
return serializeStringEscaped(`f`, options);
|
|
39
|
+
} else if (char === '\v') {
|
|
40
|
+
return serializeStringEscaped(`v`, options);
|
|
41
|
+
} else if (char === '\\') {
|
|
42
|
+
return serializeStringEscaped(`\\`, options);
|
|
43
|
+
} else if (char === '$') {
|
|
44
|
+
return serializeStringEscaped(`$`, options);
|
|
45
|
+
} else {
|
|
46
|
+
const code = char.codePointAt(0)!;
|
|
47
|
+
if (code <= 0x7f) {
|
|
48
|
+
return serializeStringEscaped(`x${code.toString(16).padStart(2, '0')}`, options);
|
|
49
|
+
} else if (code >= 0xd800 && code <= 0xdfff) {
|
|
50
|
+
// 无效的代理对
|
|
51
|
+
return serializeStringContent('�', options);
|
|
52
|
+
} else {
|
|
53
|
+
return serializeStringEscaped(`u{${code.toString(16)}}`, options);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 将 MiraScript 字符串序列化为 MiraScript 字面量。
|
|
60
|
+
*/
|
|
61
|
+
export function serializeStringImpl(value: string, options: Readonly<SerializeOptions>): string {
|
|
62
|
+
const oq = options.serializeStringQuote(STRING_QUOTE, true, options);
|
|
63
|
+
const cq = options.serializeStringQuote(STRING_QUOTE, false, options);
|
|
64
|
+
if (value.length === 0) {
|
|
65
|
+
return oq + cq;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let ret = oq;
|
|
69
|
+
let lastIndex = 0;
|
|
70
|
+
|
|
71
|
+
// 当开头字符是 \p{M} 时,使用转义序列化
|
|
72
|
+
while (value.length > lastIndex) {
|
|
73
|
+
const cp = value.codePointAt(lastIndex)!;
|
|
74
|
+
const ch = String.fromCodePoint(cp);
|
|
75
|
+
if (!STRING_MARK.test(ch)) break;
|
|
76
|
+
ret += serializeStringEscaped(`u{${cp.toString(16)}}`, options);
|
|
77
|
+
lastIndex += ch.length;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 序列化字符串内容,遇到特殊字符时使用转义序列化
|
|
81
|
+
STRING_REG.lastIndex = lastIndex;
|
|
82
|
+
let match: RegExpExecArray | null;
|
|
83
|
+
while ((match = STRING_REG.exec(value)) !== null) {
|
|
84
|
+
ret += serializeStringContent(value.slice(lastIndex, match.index), options);
|
|
85
|
+
lastIndex = STRING_REG.lastIndex;
|
|
86
|
+
ret += serializeSpecialChar(match[0], options);
|
|
87
|
+
}
|
|
88
|
+
ret += serializeStringContent(value.slice(lastIndex), options);
|
|
89
|
+
ret += cq;
|
|
90
|
+
return ret;
|
|
91
|
+
}
|
package/src/helpers/utils.ts
CHANGED
|
@@ -39,12 +39,13 @@ const SPECIAL_KEYS = new Set(getOwnPropertyNames(Object.prototype));
|
|
|
39
39
|
* Set property on an vm record.
|
|
40
40
|
*/
|
|
41
41
|
export const setRecord = (obj: Record<string, VmConst | undefined>, key: string, value: VmConst | undefined): void => {
|
|
42
|
+
value ??= null;
|
|
42
43
|
if (!SPECIAL_KEYS.has(key)) {
|
|
43
|
-
obj[key] = value
|
|
44
|
+
obj[key] = value;
|
|
44
45
|
} else {
|
|
45
46
|
defineProperty(obj, key, {
|
|
46
47
|
__proto__: null,
|
|
47
|
-
value
|
|
48
|
+
value,
|
|
48
49
|
configurable: true,
|
|
49
50
|
writable: true,
|
|
50
51
|
enumerable: true,
|
|
@@ -59,3 +60,11 @@ export const getRecord = (obj: VmRecord, key: string): VmConst | undefined => {
|
|
|
59
60
|
if (!hasOwnEnumerable(obj, key)) return undefined;
|
|
60
61
|
return obj[key] ?? null;
|
|
61
62
|
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Checks if a value is Promise-like (i.e., has a `then` method).
|
|
66
|
+
*/
|
|
67
|
+
export const isPromiseLike = (value: unknown): value is PromiseLike<unknown> => {
|
|
68
|
+
if (value == null || typeof value != 'object') return false;
|
|
69
|
+
return typeof (value as PromiseLike<unknown>).then == 'function';
|
|
70
|
+
};
|
package/src/index.ts
CHANGED
package/src/subtle.ts
CHANGED
|
@@ -6,7 +6,7 @@ export * as convert from './helpers/convert/index.js';
|
|
|
6
6
|
export { DefaultVmContext } from './vm/types/context.js';
|
|
7
7
|
export * as operations from './vm/operations/index.js';
|
|
8
8
|
export {
|
|
9
|
-
|
|
9
|
+
serializeForDisplay,
|
|
10
10
|
serialize,
|
|
11
11
|
serializeNil,
|
|
12
12
|
serializeBoolean,
|
|
@@ -16,7 +16,7 @@ export {
|
|
|
16
16
|
serializeArray,
|
|
17
17
|
serializeRecord,
|
|
18
18
|
type SerializeOptions,
|
|
19
|
-
} from './helpers/serialize.js';
|
|
19
|
+
} from './helpers/serialize/index.js';
|
|
20
20
|
export { lib, type Lib, type VmLibOption } from './vm/lib/index.js';
|
|
21
21
|
export * from './compiler/diagnostic.js';
|
|
22
22
|
export { compileVerbose } from './compiler/verbose.js';
|