@mirascript/mirascript 0.1.76 → 0.1.79
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-ZRLBJK6A.js → chunk-BPFOJ4Q6.js} +499 -470
- package/dist/chunk-BPFOJ4Q6.js.map +6 -0
- package/dist/{chunk-VI74OKFU.js → chunk-LSPCAN32.js} +291 -226
- package/dist/chunk-LSPCAN32.js.map +6 -0
- package/dist/compiler/emit/constants.d.ts +1 -1
- package/dist/compiler/emit/constants.d.ts.map +1 -1
- package/dist/compiler/emit/consts.d.ts.map +1 -1
- package/dist/compiler/emit/index.d.ts.map +1 -1
- package/dist/compiler/emit-script.d.ts.map +1 -1
- package/dist/compiler/worker.js +1 -1
- package/dist/helpers/convert/{to-boolean.d.ts → boolean.d.ts} +1 -1
- package/dist/helpers/convert/boolean.d.ts.map +1 -0
- package/dist/helpers/convert/{to-format.d.ts → format.d.ts} +1 -1
- package/dist/helpers/convert/format.d.ts.map +1 -0
- package/dist/helpers/convert/index.d.ts +4 -4
- package/dist/helpers/convert/index.d.ts.map +1 -1
- package/dist/helpers/convert/{to-number.d.ts → number.d.ts} +1 -1
- package/dist/helpers/convert/number.d.ts.map +1 -0
- package/dist/helpers/convert/{to-string.d.ts → string.d.ts} +3 -1
- package/dist/helpers/convert/string.d.ts.map +1 -0
- package/dist/helpers/error.d.ts +1 -0
- package/dist/helpers/error.d.ts.map +1 -1
- package/dist/helpers/serialize.d.ts.map +1 -1
- package/dist/helpers/types/array-like.d.ts +8 -0
- package/dist/helpers/types/array-like.d.ts.map +1 -0
- package/dist/helpers/types/basic.d.ts +26 -0
- package/dist/helpers/types/basic.d.ts.map +1 -0
- package/dist/helpers/types/composed.d.ts +12 -0
- package/dist/helpers/types/composed.d.ts.map +1 -0
- package/dist/helpers/types/const.d.ts +6 -0
- package/dist/helpers/types/const.d.ts.map +1 -0
- package/dist/helpers/types/get-type.d.ts +6 -0
- package/dist/helpers/types/get-type.d.ts.map +1 -0
- package/dist/helpers/types/index.d.ts +6 -0
- package/dist/helpers/types/index.d.ts.map +1 -0
- package/dist/helpers/types/proto.d.ts +5 -0
- package/dist/helpers/types/proto.d.ts.map +1 -0
- package/dist/helpers/utils.d.ts +9 -0
- package/dist/helpers/utils.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/subtle.js +3 -3
- package/dist/vm/lib/global/debug.d.ts.map +1 -1
- package/dist/vm/lib/global/json.d.ts +3 -2
- package/dist/vm/lib/global/json.d.ts.map +1 -1
- package/dist/vm/lib/global/math/tgamma.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/entries.d.ts +1 -1
- package/dist/vm/lib/global/sequence/entries.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/fold.d.ts +3 -0
- package/dist/vm/lib/global/sequence/fold.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/group.d.ts +3 -0
- package/dist/vm/lib/global/sequence/group.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/index.d.ts +2 -0
- package/dist/vm/lib/global/sequence/index.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/new.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/zip.d.ts +2 -2
- package/dist/vm/lib/global/sequence/zip.d.ts.map +1 -1
- package/dist/vm/lib/helpers.d.ts +2 -2
- package/dist/vm/lib/helpers.d.ts.map +1 -1
- package/dist/vm/lib/mod/index.d.ts +1 -1
- package/dist/vm/lib/mod/index.d.ts.map +1 -1
- package/dist/vm/lib/mod/matrix/bin-ops.d.ts +8 -0
- package/dist/vm/lib/mod/matrix/bin-ops.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix/fill.d.ts +6 -0
- package/dist/vm/lib/mod/matrix/fill.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix/helpers.d.ts +6 -0
- package/dist/vm/lib/mod/matrix/helpers.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix/index.d.ts +6 -0
- package/dist/vm/lib/mod/matrix/index.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix/invert.d.ts +3 -0
- package/dist/vm/lib/mod/matrix/invert.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix/size.d.ts +2 -0
- package/dist/vm/lib/mod/matrix/size.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix/transpose.d.ts +2 -0
- package/dist/vm/lib/mod/matrix/transpose.d.ts.map +1 -0
- package/dist/vm/operations/array-range.d.ts +3 -3
- package/dist/vm/operations/array-range.d.ts.map +1 -1
- package/dist/vm/operations/call.d.ts +1 -1
- package/dist/vm/operations/call.d.ts.map +1 -1
- package/dist/vm/operations/compound.d.ts +1 -13
- package/dist/vm/operations/compound.d.ts.map +1 -1
- package/dist/vm/operations/index.d.ts +3 -0
- package/dist/vm/operations/index.d.ts.map +1 -1
- package/dist/vm/operations/iterable.d.ts +6 -0
- package/dist/vm/operations/iterable.d.ts.map +1 -0
- package/dist/vm/operations/record.d.ts +6 -0
- package/dist/vm/operations/record.d.ts.map +1 -0
- package/dist/vm/operations/slice.d.ts.map +1 -1
- package/dist/vm/operations/spread.d.ts +6 -0
- package/dist/vm/operations/spread.d.ts.map +1 -0
- package/dist/vm/operations/utils.d.ts.map +1 -1
- package/dist/vm/types/extern/access.d.ts +5 -0
- package/dist/vm/types/extern/access.d.ts.map +1 -0
- package/dist/vm/types/{extern.d.ts → extern/index.d.ts} +3 -3
- package/dist/vm/types/extern/index.d.ts.map +1 -0
- package/dist/vm/types/extern/tag.d.ts +3 -0
- package/dist/vm/types/extern/tag.d.ts.map +1 -0
- package/dist/vm/types/extern/utils.d.ts +13 -0
- package/dist/vm/types/extern/utils.d.ts.map +1 -0
- package/dist/vm/types/index.d.ts +3 -3
- package/dist/vm/types/index.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/compiler/compile-fast.ts +1 -1
- package/src/compiler/diagnostic.ts +2 -2
- package/src/compiler/emit/constants.ts +1 -1
- package/src/compiler/emit/consts.ts +0 -1
- package/src/compiler/emit/index.ts +1 -7
- package/src/compiler/emit/sourcemap.ts +1 -1
- package/src/compiler/emit-script.ts +1 -0
- package/src/compiler/load-module.ts +5 -1
- package/src/helpers/convert/{to-boolean.ts → boolean.ts} +1 -1
- package/src/helpers/convert/{to-format.ts → format.ts} +1 -1
- package/src/helpers/convert/index.ts +4 -4
- package/src/helpers/convert/{to-number.ts → number.ts} +16 -32
- package/src/helpers/convert/{to-string.ts → string.ts} +5 -4
- package/src/helpers/error.ts +3 -1
- package/src/helpers/serialize.ts +45 -44
- package/src/helpers/types/array-like.ts +32 -0
- package/src/helpers/types/basic.ts +82 -0
- package/src/helpers/types/composed.ts +27 -0
- package/src/helpers/types/const.ts +44 -0
- package/src/helpers/types/get-type.ts +16 -0
- package/src/helpers/types/index.ts +5 -0
- package/src/helpers/types/proto.ts +21 -0
- package/src/helpers/utils.ts +33 -0
- package/src/vm/lib/global/debug.ts +4 -8
- package/src/vm/lib/global/json.ts +21 -9
- package/src/vm/lib/global/math/tgamma.ts +8 -14
- package/src/vm/lib/global/sequence/all-any.ts +1 -1
- package/src/vm/lib/global/sequence/entries.ts +6 -1
- package/src/vm/lib/global/sequence/find.ts +1 -1
- package/src/vm/lib/global/sequence/fold.ts +30 -0
- package/src/vm/lib/global/sequence/group.ts +37 -0
- package/src/vm/lib/global/sequence/index.ts +2 -0
- package/src/vm/lib/global/sequence/map-filter.ts +3 -3
- package/src/vm/lib/global/sequence/new.ts +9 -3
- package/src/vm/lib/global/sequence/sort.ts +1 -1
- package/src/vm/lib/global/sequence/unique.ts +1 -1
- package/src/vm/lib/global/sequence/with.ts +5 -5
- package/src/vm/lib/global/sequence/zip.ts +21 -10
- package/src/vm/lib/global/time.ts +1 -1
- package/src/vm/lib/helpers.ts +12 -5
- package/src/vm/lib/mod/index.ts +1 -1
- package/src/vm/lib/mod/matrix/bin-ops.ts +291 -0
- package/src/vm/lib/mod/matrix/fill.ts +109 -0
- package/src/vm/lib/mod/matrix/helpers.ts +26 -0
- package/src/vm/lib/mod/matrix/index.ts +5 -0
- package/src/vm/lib/mod/matrix/invert.ts +122 -0
- package/src/vm/lib/mod/matrix/size.ts +15 -0
- package/src/vm/lib/mod/matrix/transpose.ts +32 -0
- package/src/vm/operations/array-range.ts +15 -27
- package/src/vm/operations/call.ts +2 -2
- package/src/vm/operations/compound.ts +5 -125
- package/src/vm/operations/helpers.ts +1 -1
- package/src/vm/operations/index.ts +3 -0
- package/src/vm/operations/iterable.ts +40 -0
- package/src/vm/operations/record.ts +33 -0
- package/src/vm/operations/slice.ts +23 -22
- package/src/vm/operations/spread.ts +57 -0
- package/src/vm/operations/type-check.ts +1 -1
- package/src/vm/operations/utils.ts +45 -37
- package/src/vm/types/boundary.ts +2 -2
- package/src/vm/types/extern/access.ts +24 -0
- package/src/vm/types/extern/index.ts +124 -0
- package/src/vm/types/extern/tag.ts +58 -0
- package/src/vm/types/extern/utils.ts +55 -0
- package/src/vm/types/function.ts +1 -1
- package/src/vm/types/index.ts +3 -3
- package/dist/chunk-VI74OKFU.js.map +0 -6
- package/dist/chunk-ZRLBJK6A.js.map +0 -6
- package/dist/helpers/convert/to-boolean.d.ts.map +0 -1
- package/dist/helpers/convert/to-format.d.ts.map +0 -1
- package/dist/helpers/convert/to-number.d.ts.map +0 -1
- package/dist/helpers/convert/to-string.d.ts.map +0 -1
- package/dist/helpers/types.d.ts +0 -58
- package/dist/helpers/types.d.ts.map +0 -1
- package/dist/vm/lib/mod/matrix.d.ts +0 -15
- package/dist/vm/lib/mod/matrix.d.ts.map +0 -1
- package/dist/vm/types/extern.d.ts.map +0 -1
- package/src/helpers/types.ts +0 -283
- package/src/vm/lib/mod/matrix.ts +0 -590
- package/src/vm/types/extern.ts +0 -197
package/src/helpers/error.ts
CHANGED
|
@@ -6,12 +6,14 @@ import type { VmAny } from '../vm/types/index.js';
|
|
|
6
6
|
export class VmError extends Error {
|
|
7
7
|
constructor(
|
|
8
8
|
message: string,
|
|
9
|
+
// eslint-disable-next-line unicorn/custom-error-definition
|
|
9
10
|
readonly recovered: VmAny,
|
|
10
11
|
) {
|
|
11
12
|
super(message);
|
|
12
|
-
this.name = 'VmError';
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
override readonly name = 'VmError';
|
|
16
|
+
|
|
15
17
|
/** 从其他错误构造 */
|
|
16
18
|
static from(prefix: string, error: unknown, recovered: VmAny): VmError {
|
|
17
19
|
if (prefix) {
|
package/src/helpers/serialize.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { REG_IDENTIFIER_FULL, REG_ORDINAL_FULL } from '@mirascript/constants';
|
|
2
2
|
import type { VmArray, VmExtern, VmFunction, VmModule, VmAny, VmRecord } from '../vm/index.js';
|
|
3
|
-
import { entries, hasOwn
|
|
3
|
+
import { entries, hasOwn } from '../helpers/utils.js';
|
|
4
4
|
import {
|
|
5
5
|
getVmFunctionInfo,
|
|
6
6
|
isVmArray,
|
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
isVmFunction,
|
|
10
10
|
isVmModule,
|
|
11
11
|
isVmRecord,
|
|
12
|
-
} from './types.js';
|
|
12
|
+
} from './types/index.js';
|
|
13
|
+
import { numberToString } from './convert/string.js';
|
|
13
14
|
|
|
14
15
|
/** 序列化 nil 值 */
|
|
15
16
|
export function serializeNil(): string {
|
|
@@ -23,13 +24,7 @@ export function serializeBoolean(value: boolean): string {
|
|
|
23
24
|
|
|
24
25
|
/** 序列化数字 */
|
|
25
26
|
export function serializeNumber(value: number): string {
|
|
26
|
-
|
|
27
|
-
if (!isFinite(value)) return value < 0 ? '-inf' : 'inf';
|
|
28
|
-
if (value === 0) {
|
|
29
|
-
if (1 / value < 0) return '-0';
|
|
30
|
-
return '0';
|
|
31
|
-
}
|
|
32
|
-
return String(value);
|
|
27
|
+
return numberToString(value, true);
|
|
33
28
|
}
|
|
34
29
|
|
|
35
30
|
/**
|
|
@@ -49,6 +44,44 @@ function serializeStringContent(value: string, options: Readonly<SerializeOption
|
|
|
49
44
|
const STRING_QUOTE = `'`;
|
|
50
45
|
const STRING_REG = new RegExp(String.raw`[${STRING_QUOTE}\\\$\p{C}\u2028\u2029]`, 'gu');
|
|
51
46
|
const STRING_MARK = /^[\p{M}]$/u;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 序列化为特殊字符
|
|
50
|
+
*/
|
|
51
|
+
function serializeSpecialChar(char: string, options: Readonly<SerializeOptions>): string {
|
|
52
|
+
if (char === STRING_QUOTE) {
|
|
53
|
+
return serializeStringEscaped(STRING_QUOTE, options);
|
|
54
|
+
} else if (char === '\0') {
|
|
55
|
+
return serializeStringEscaped(`0`, options);
|
|
56
|
+
} else if (char === '\n') {
|
|
57
|
+
return serializeStringEscaped(`n`, options);
|
|
58
|
+
} else if (char === '\r') {
|
|
59
|
+
return serializeStringEscaped(`r`, options);
|
|
60
|
+
} else if (char === '\t') {
|
|
61
|
+
return serializeStringEscaped(`t`, options);
|
|
62
|
+
} else if (char === '\b') {
|
|
63
|
+
return serializeStringEscaped(`b`, options);
|
|
64
|
+
} else if (char === '\f') {
|
|
65
|
+
return serializeStringEscaped(`f`, options);
|
|
66
|
+
} else if (char === '\v') {
|
|
67
|
+
return serializeStringEscaped(`v`, options);
|
|
68
|
+
} else if (char === '\\') {
|
|
69
|
+
return serializeStringEscaped(`\\`, options);
|
|
70
|
+
} else if (char === '$') {
|
|
71
|
+
return serializeStringEscaped(`$`, options);
|
|
72
|
+
} else {
|
|
73
|
+
const code = char.codePointAt(0)!;
|
|
74
|
+
if (code <= 0x7f) {
|
|
75
|
+
return serializeStringEscaped(`x${code.toString(16).padStart(2, '0')}`, options);
|
|
76
|
+
} else if (code >= 0xd800 && code <= 0xdfff) {
|
|
77
|
+
// 无效的代理对
|
|
78
|
+
return serializeStringContent('�', options);
|
|
79
|
+
} else {
|
|
80
|
+
return serializeStringEscaped(`u{${code.toString(16)}}`, options);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
52
85
|
/**
|
|
53
86
|
* 将 MiraScript 字符串序列化为 MiraScript 字面量。
|
|
54
87
|
*/
|
|
@@ -67,8 +100,7 @@ function serializeStringImpl(value: string, options: Readonly<SerializeOptions>)
|
|
|
67
100
|
const cp = value.codePointAt(lastIndex)!;
|
|
68
101
|
const ch = String.fromCodePoint(cp);
|
|
69
102
|
if (!STRING_MARK.test(ch)) break;
|
|
70
|
-
|
|
71
|
-
ret += c;
|
|
103
|
+
ret += serializeStringEscaped(`u{${cp.toString(16)}}`, options);
|
|
72
104
|
lastIndex += ch.length;
|
|
73
105
|
}
|
|
74
106
|
|
|
@@ -76,40 +108,9 @@ function serializeStringImpl(value: string, options: Readonly<SerializeOptions>)
|
|
|
76
108
|
STRING_REG.lastIndex = lastIndex;
|
|
77
109
|
let match: RegExpExecArray | null;
|
|
78
110
|
while ((match = STRING_REG.exec(value)) !== null) {
|
|
79
|
-
const char = match[0];
|
|
80
111
|
ret += serializeStringContent(value.slice(lastIndex, match.index), options);
|
|
81
112
|
lastIndex = STRING_REG.lastIndex;
|
|
82
|
-
|
|
83
|
-
ret += serializeStringEscaped(STRING_QUOTE, options);
|
|
84
|
-
} else if (char === '\0') {
|
|
85
|
-
ret += serializeStringEscaped(`0`, options);
|
|
86
|
-
} else if (char === '\n') {
|
|
87
|
-
ret += serializeStringEscaped(`n`, options);
|
|
88
|
-
} else if (char === '\r') {
|
|
89
|
-
ret += serializeStringEscaped(`r`, options);
|
|
90
|
-
} else if (char === '\t') {
|
|
91
|
-
ret += serializeStringEscaped(`t`, options);
|
|
92
|
-
} else if (char === '\b') {
|
|
93
|
-
ret += serializeStringEscaped(`b`, options);
|
|
94
|
-
} else if (char === '\f') {
|
|
95
|
-
ret += serializeStringEscaped(`f`, options);
|
|
96
|
-
} else if (char === '\v') {
|
|
97
|
-
ret += serializeStringEscaped(`v`, options);
|
|
98
|
-
} else if (char === '\\') {
|
|
99
|
-
ret += serializeStringEscaped(`\\`, options);
|
|
100
|
-
} else if (char === '$') {
|
|
101
|
-
ret += serializeStringEscaped(`$`, options);
|
|
102
|
-
} else {
|
|
103
|
-
const code = char.codePointAt(0)!;
|
|
104
|
-
if (code <= 0x7f) {
|
|
105
|
-
ret += serializeStringEscaped(`x${code.toString(16).padStart(2, '0')}`, options);
|
|
106
|
-
} else if (code >= 0xd800 && code <= 0xdfff) {
|
|
107
|
-
// 无效的代理对
|
|
108
|
-
ret += serializeStringContent('�', options);
|
|
109
|
-
} else {
|
|
110
|
-
ret += serializeStringEscaped(`u{${code.toString(16)}}`, options);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
+
ret += serializeSpecialChar(match[0], options);
|
|
113
114
|
}
|
|
114
115
|
ret += serializeStringContent(value.slice(lastIndex), options);
|
|
115
116
|
ret += cq;
|
|
@@ -177,7 +178,7 @@ const { valueOf } = Object.prototype;
|
|
|
177
178
|
function customValueOf(value: VmRecord): VmAny | undefined {
|
|
178
179
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
179
180
|
const thisValueOf = value.valueOf;
|
|
180
|
-
if (typeof thisValueOf
|
|
181
|
+
if (typeof thisValueOf !== 'function' || thisValueOf === valueOf) {
|
|
181
182
|
return undefined;
|
|
182
183
|
}
|
|
183
184
|
const customValue = thisValueOf.call(value) as VmAny | undefined;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { VmRecord } from '../../vm/types/index.js';
|
|
2
|
+
import { VM_ARRAY_MAX_LENGTH } from '../constants.js';
|
|
3
|
+
import { keys } from '../utils.js';
|
|
4
|
+
|
|
5
|
+
/** 检查是否为仅包含从 0 开始的连续数字键的 MiraScript 记录 */
|
|
6
|
+
export function isVmArrayLikeRecordByEntries(entries: ReadonlyArray<readonly [string, unknown]>): boolean {
|
|
7
|
+
const { length } = entries;
|
|
8
|
+
if (length === 0) return true;
|
|
9
|
+
if (length > VM_ARRAY_MAX_LENGTH) return false;
|
|
10
|
+
const firstKey = entries[0]![0];
|
|
11
|
+
if (firstKey !== '0') return false;
|
|
12
|
+
const lastKey = entries[length - 1]![0];
|
|
13
|
+
if (lastKey !== String(length - 1)) return false;
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** 检查是否为仅包含从 0 开始的连续数字键的 MiraScript 记录 */
|
|
18
|
+
export function isVmArrayLikeRecordByKeys(keys: readonly string[]): boolean {
|
|
19
|
+
const { length } = keys;
|
|
20
|
+
if (length === 0) return true;
|
|
21
|
+
if (length > VM_ARRAY_MAX_LENGTH) return false;
|
|
22
|
+
const firstKey = keys[0]!;
|
|
23
|
+
if (firstKey !== '0') return false;
|
|
24
|
+
const lastKey = keys[length - 1]!;
|
|
25
|
+
if (lastKey !== String(length - 1)) return false;
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** 检查是否为仅包含从 0 开始的连续数字键的 MiraScript 记录 */
|
|
30
|
+
export function isVmArrayLikeRecord(value: VmRecord): boolean {
|
|
31
|
+
return isVmArrayLikeRecordByKeys(keys(value));
|
|
32
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { VmScript } from '../../compiler/index.js';
|
|
2
|
+
import type {
|
|
3
|
+
VmAny,
|
|
4
|
+
VmArray,
|
|
5
|
+
VmContext,
|
|
6
|
+
VmExtern,
|
|
7
|
+
VmFunction,
|
|
8
|
+
VmFunctionInfo,
|
|
9
|
+
VmFunctionLike,
|
|
10
|
+
VmImmutable,
|
|
11
|
+
VmModule,
|
|
12
|
+
VmPrimitive,
|
|
13
|
+
VmRecord,
|
|
14
|
+
} from '../../vm/types/index.js';
|
|
15
|
+
import type { VmWrapper } from '../../vm/types/wrapper.js';
|
|
16
|
+
import { kVmContext, kVmExtern, kVmFunction, kVmModule, kVmScript, kVmWrapper } from '../constants.js';
|
|
17
|
+
import { isArray } from '../utils.js';
|
|
18
|
+
|
|
19
|
+
/** 检查是否为 Mirascript 脚本 */
|
|
20
|
+
export function isVmScript(value: unknown): value is VmScript {
|
|
21
|
+
return typeof value === 'function' && kVmScript in value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** 检查是否为执行上下文 */
|
|
25
|
+
export function isVmContext(context: unknown): context is VmContext {
|
|
26
|
+
return context != null && typeof context == 'object' && kVmContext in context;
|
|
27
|
+
}
|
|
28
|
+
/** 检查是否为 Mirascript 函数 */
|
|
29
|
+
export function isVmFunction<T extends VmFunctionLike>(value: unknown): value is VmFunction<T> {
|
|
30
|
+
return typeof value == 'function' && kVmFunction in value;
|
|
31
|
+
}
|
|
32
|
+
/** 检查是否为 Mirascript 函数,并获取其信息 */
|
|
33
|
+
export function getVmFunctionInfo(value: unknown): VmFunctionInfo | undefined {
|
|
34
|
+
if (typeof value != 'function') return undefined;
|
|
35
|
+
return (value as VmFunction)[kVmFunction];
|
|
36
|
+
}
|
|
37
|
+
/** 检查值是否为 MiraScript 包装器 */
|
|
38
|
+
export function isVmWrapper<T extends object>(value: unknown): value is VmWrapper<T> {
|
|
39
|
+
return value != null && typeof value == 'object' && kVmWrapper in value;
|
|
40
|
+
}
|
|
41
|
+
/** 检查值是否为 Mirascript 模块 */
|
|
42
|
+
export function isVmModule<T extends Record<string, VmImmutable>>(value: unknown): value is VmModule<T> {
|
|
43
|
+
return value != null && typeof value == 'object' && kVmModule in value;
|
|
44
|
+
}
|
|
45
|
+
/** 检查值是否为 Mirascript 外部值 */
|
|
46
|
+
export function isVmExtern<T extends object>(value: unknown): value is VmExtern<T> {
|
|
47
|
+
return value != null && typeof value == 'object' && kVmExtern in value;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** 检查值是否为 Mirascript 可调用值 */
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
52
|
+
export function isVmCallable<E extends Function, F extends VmFunctionLike>(
|
|
53
|
+
value: unknown,
|
|
54
|
+
): value is VmFunction<F> | VmExtern<E> {
|
|
55
|
+
return isVmFunction<F>(value) || (isVmExtern<E>(value) && typeof value.value == 'function');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** 检查值是否为 Mirascript 原始值 */
|
|
59
|
+
export function isVmPrimitive(value: unknown): value is VmPrimitive {
|
|
60
|
+
if (value === null || typeof value == 'number' || typeof value == 'string' || typeof value == 'boolean') {
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
62
|
+
value as VmPrimitive satisfies typeof value;
|
|
63
|
+
value satisfies VmPrimitive;
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** 检查值是否为 Mirascript 数组 */
|
|
70
|
+
export function isVmArray(value: VmAny): value is VmArray {
|
|
71
|
+
if (!isArray(value)) return false;
|
|
72
|
+
value as VmArray satisfies VmArray;
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** 检查值是否为 Mirascript 记录 */
|
|
77
|
+
export function isVmRecord(value: VmAny): value is VmRecord {
|
|
78
|
+
if (value == null || typeof value != 'object') return false;
|
|
79
|
+
if (isVmWrapper(value) || isVmArray(value)) return false;
|
|
80
|
+
value satisfies VmRecord;
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { VmAny, VmImmutable, VmValue } from '../../vm/types/index.js';
|
|
2
|
+
import { isVmFunction, isVmModule, isVmWrapper } from './basic.js';
|
|
3
|
+
import { isVmConst } from './const.js';
|
|
4
|
+
|
|
5
|
+
/** 检查是否为 Mirascript 不可变值 */
|
|
6
|
+
export function isVmImmutable(value: VmAny): value is VmImmutable;
|
|
7
|
+
/** 检查是否为 Mirascript 不可变值 */
|
|
8
|
+
export function isVmImmutable(value: unknown, checkDeep: boolean): value is VmImmutable;
|
|
9
|
+
/** 检查是否为 Mirascript 不可变值 */
|
|
10
|
+
export function isVmImmutable(value: unknown, checkDeep = false): value is VmImmutable {
|
|
11
|
+
return isVmModule(value) || isVmFunction(value) || isVmConst(value, checkDeep);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** 检查是否为 Mirascript 合法值 */
|
|
15
|
+
export function isVmValue(value: VmAny): value is VmValue;
|
|
16
|
+
/** 检查是否为 Mirascript 合法值 */
|
|
17
|
+
export function isVmValue(value: unknown, checkDeep: boolean): value is VmValue;
|
|
18
|
+
/** 检查是否为 Mirascript 合法值 */
|
|
19
|
+
export function isVmValue(value: unknown, checkDeep = false): value is VmValue {
|
|
20
|
+
return isVmWrapper(value) || isVmFunction(value) || isVmConst(value, checkDeep);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** 检查是否为 Mirascript 值 */
|
|
24
|
+
export function isVmAny(value: unknown, checkDeep: boolean): value is VmAny {
|
|
25
|
+
if (value == null) return true;
|
|
26
|
+
return isVmValue(value, checkDeep);
|
|
27
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { VmAny, VmArray, VmConst, VmRecord } from '../../vm/types/index.js';
|
|
2
|
+
import { isArray, values } from '../utils.js';
|
|
3
|
+
import { isVmWrapper } from './basic.js';
|
|
4
|
+
import { isPlainArray, isPlainObject } from './proto.js';
|
|
5
|
+
|
|
6
|
+
const MAX_DEPTH = 16;
|
|
7
|
+
/** 检查是否为 Mirascript 数组 */
|
|
8
|
+
function isVmArrayDeep(value: readonly unknown[], depth: number): value is VmArray {
|
|
9
|
+
if (!isPlainArray(value)) return false;
|
|
10
|
+
if (depth <= 0) return true;
|
|
11
|
+
const inner_depth = depth - 1;
|
|
12
|
+
return value.every((item) => isVmConstInner(item, inner_depth));
|
|
13
|
+
}
|
|
14
|
+
/** 检查是否为 Mirascript 记录 */
|
|
15
|
+
function isVmRecordDeep(value: object, depth: number): value is VmRecord {
|
|
16
|
+
if (!isPlainObject(value)) return false;
|
|
17
|
+
if (depth <= 0) return true;
|
|
18
|
+
const inner_depth = depth - 1;
|
|
19
|
+
return values(value).every((value) => isVmConstInner(value, inner_depth));
|
|
20
|
+
}
|
|
21
|
+
/** 检查是否为 Mirascript 值语义值 */
|
|
22
|
+
function isVmConstInner(value: unknown, depth: number): value is VmConst {
|
|
23
|
+
if (value == null) return true; // undefined 在复合类型内部被视为 nil
|
|
24
|
+
if (typeof value == 'string' || typeof value == 'number' || typeof value == 'boolean') return true;
|
|
25
|
+
if (typeof value == 'object') {
|
|
26
|
+
if (isVmWrapper(value)) return false;
|
|
27
|
+
if (isArray(value)) {
|
|
28
|
+
return isVmArrayDeep(value, depth);
|
|
29
|
+
} else {
|
|
30
|
+
return isVmRecordDeep(value, depth);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return false; // Other types are not valid
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 检查是否为 Mirascript 值语义值 */
|
|
37
|
+
export function isVmConst(value: VmAny): value is VmConst;
|
|
38
|
+
/** 检查是否为 Mirascript 值语义值 */
|
|
39
|
+
export function isVmConst(value: unknown, checkDeep: boolean): value is VmConst;
|
|
40
|
+
/** 检查是否为 Mirascript 值语义值 */
|
|
41
|
+
export function isVmConst(value: unknown, checkDeep = false): value is VmConst {
|
|
42
|
+
if (value === undefined) return false;
|
|
43
|
+
return isVmConstInner(value, checkDeep ? MAX_DEPTH : 0);
|
|
44
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { VmValue, VmTypeName, VmAny } from '../../vm/index.js';
|
|
2
|
+
import { isVmWrapper, isVmArray } from './basic.js';
|
|
3
|
+
|
|
4
|
+
/** 获取 MiraScript 类型 */
|
|
5
|
+
export function getVmType(value: VmValue): VmTypeName;
|
|
6
|
+
/** 获取 MiraScript 类型 */
|
|
7
|
+
export function getVmType(value: VmAny): VmTypeName | 'uninitialized';
|
|
8
|
+
/** 获取 MiraScript 类型 */
|
|
9
|
+
export function getVmType(value: VmAny): VmTypeName | 'uninitialized' {
|
|
10
|
+
if (value === undefined) return 'uninitialized';
|
|
11
|
+
if (value === null) return 'nil';
|
|
12
|
+
if (isVmWrapper(value)) return value.type;
|
|
13
|
+
if (isVmArray(value)) return 'array';
|
|
14
|
+
if (typeof value == 'object') return 'record';
|
|
15
|
+
return typeof value as VmTypeName;
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getPrototypeOf, hasOwn, isArray } from '../utils.js';
|
|
2
|
+
|
|
3
|
+
/** 检查是否为普通数组 */
|
|
4
|
+
export function isPlainArray(value: readonly unknown[]): boolean {
|
|
5
|
+
// value 的原型应当为 Array.prototype
|
|
6
|
+
const proto: unknown = getPrototypeOf(value);
|
|
7
|
+
// 使用 isArray 检查原型是否为 Array.prototype,避免直接比较原型对象,防止跨环境问题
|
|
8
|
+
return isArray(proto) && hasOwn(proto, 'push');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** 检查是否为普通对象或空原型对象 */
|
|
12
|
+
export function isPlainObject(value: object): boolean {
|
|
13
|
+
// value 的原型应当为 Object.prototype 或 null
|
|
14
|
+
const proto1: unknown = getPrototypeOf(value);
|
|
15
|
+
if (proto1 == null) return true;
|
|
16
|
+
// Object.prototype 的原型应当为 null
|
|
17
|
+
const proto2: unknown = getPrototypeOf(proto1);
|
|
18
|
+
if (proto2 != null) return false;
|
|
19
|
+
// 检查是否具有 Object.prototype 的方法,避免直接比较原型对象,防止跨环境问题
|
|
20
|
+
return hasOwn(proto1, 'hasOwnProperty');
|
|
21
|
+
}
|
package/src/helpers/utils.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { VmConst, VmRecord } from '../vm/index.js';
|
|
2
|
+
|
|
1
3
|
export const { isArray } = Array;
|
|
2
4
|
export const {
|
|
3
5
|
isFinite,
|
|
@@ -26,3 +28,34 @@ export const hasOwnEnumerable = Function.call.bind(
|
|
|
26
28
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
27
29
|
Object.prototype.propertyIsEnumerable,
|
|
28
30
|
) as (o: object, v: PropertyKey) => boolean;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Snapshot the inherited keys that require data-property semantics when written
|
|
34
|
+
* to a VM record. The host is expected not to mutate `Object.prototype` after
|
|
35
|
+
* MiraScript has been initialized.
|
|
36
|
+
*/
|
|
37
|
+
const SPECIAL_KEYS = new Set(getOwnPropertyNames(Object.prototype));
|
|
38
|
+
/**
|
|
39
|
+
* Set property on an vm record.
|
|
40
|
+
*/
|
|
41
|
+
export const setRecord = (obj: Record<string, VmConst | undefined>, key: string, value: VmConst | undefined): void => {
|
|
42
|
+
if (!SPECIAL_KEYS.has(key)) {
|
|
43
|
+
obj[key] = value ?? null;
|
|
44
|
+
} else {
|
|
45
|
+
defineProperty(obj, key, {
|
|
46
|
+
__proto__: null,
|
|
47
|
+
value: value ?? null,
|
|
48
|
+
configurable: true,
|
|
49
|
+
writable: true,
|
|
50
|
+
enumerable: true,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get property from an vm record.
|
|
57
|
+
*/
|
|
58
|
+
export const getRecord = (obj: VmRecord, key: string): VmConst | undefined => {
|
|
59
|
+
if (!hasOwnEnumerable(obj, key)) return undefined;
|
|
60
|
+
return obj[key] ?? null;
|
|
61
|
+
};
|
|
@@ -33,7 +33,7 @@ function serializeValue(
|
|
|
33
33
|
format: SerializeFormat,
|
|
34
34
|
): string | null | PromiseLike<string> {
|
|
35
35
|
const { serializer } = options;
|
|
36
|
-
if (serializer
|
|
36
|
+
if (serializer === defaultSerializer || serializer === null) {
|
|
37
37
|
return defaultSerializer(arg, format);
|
|
38
38
|
}
|
|
39
39
|
try {
|
|
@@ -113,11 +113,7 @@ const printParser: PrintOptions['parser'] = function (args) {
|
|
|
113
113
|
templates.push(i < values.length - 1 ? ' ' : '');
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
return {
|
|
117
|
-
templates,
|
|
118
|
-
values,
|
|
119
|
-
formats,
|
|
120
|
-
};
|
|
116
|
+
return { templates, values, formats };
|
|
121
117
|
};
|
|
122
118
|
|
|
123
119
|
/** 默认格式化函数 */
|
|
@@ -234,9 +230,9 @@ if (typeof location != 'undefined') {
|
|
|
234
230
|
panic.prefix = [badge, `${common} background: #d23d3d; color: #fff;`, reset];
|
|
235
231
|
} else {
|
|
236
232
|
if (supportsColor.stdout) {
|
|
237
|
-
debug_print.prefix = ['\
|
|
233
|
+
debug_print.prefix = ['\u{1B}[44;37m MiraScript \u{1B}[0m'];
|
|
238
234
|
}
|
|
239
235
|
if (supportsColor.stderr) {
|
|
240
|
-
panic.prefix = ['\
|
|
236
|
+
panic.prefix = ['\u{1B}[41;37m MiraScript \u{1B}[0m'];
|
|
241
237
|
}
|
|
242
238
|
}
|
|
@@ -1,19 +1,31 @@
|
|
|
1
|
-
import { isVmExtern, isVmModule } from '../../types/index.js';
|
|
1
|
+
import { isVmExtern, isVmModule, type VmValue } from '../../types/index.js';
|
|
2
2
|
import { expectString, required, rethrowError, VmLib } from '../helpers.js';
|
|
3
3
|
const { parse, stringify } = JSON;
|
|
4
4
|
|
|
5
5
|
export const to_json = VmLib(
|
|
6
6
|
(data) => {
|
|
7
7
|
required('data', data, null);
|
|
8
|
-
if (isVmExtern(data) || isVmModule(data)) {
|
|
9
|
-
try {
|
|
10
|
-
return stringify(data.value) ?? null;
|
|
11
|
-
} catch (ex) {
|
|
12
|
-
rethrowError('Failed to convert extern to JSON', ex, '{}');
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
8
|
if (typeof data == 'function') return null;
|
|
16
|
-
return stringify(data)
|
|
9
|
+
return stringify(data, (key, value: VmValue) => {
|
|
10
|
+
if (typeof value == 'function') {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
if (isVmModule(value)) {
|
|
14
|
+
return value.value as JSONValue;
|
|
15
|
+
}
|
|
16
|
+
if (isVmExtern(value)) {
|
|
17
|
+
const extern = value.value;
|
|
18
|
+
if ('toJSON' in extern && typeof extern.toJSON == 'function') {
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
20
|
+
return extern.toJSON() as JSONValue;
|
|
21
|
+
}
|
|
22
|
+
if (typeof extern == 'function') {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
return extern as JSONValue;
|
|
26
|
+
}
|
|
27
|
+
return value as JSONValue;
|
|
28
|
+
});
|
|
17
29
|
},
|
|
18
30
|
{
|
|
19
31
|
summary: '将数据转换为 JSON 字符串',
|
|
@@ -81,22 +81,16 @@ function sinpi(x: number): number {
|
|
|
81
81
|
const N = 12;
|
|
82
82
|
|
|
83
83
|
// static const double g = 6.024680040776729583740234375;
|
|
84
|
-
const GMHALF = 5.
|
|
84
|
+
const GMHALF = 5.524680040776729583740234375 as const;
|
|
85
85
|
|
|
86
86
|
const SNUM = [
|
|
87
|
-
23_531_376_880.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
31_426_415.585_400_194_380_614_231_628_318_205_362_874_684_987_64,
|
|
95
|
-
2_876_370.628_935_372_441_225_409_051_620_849_613_599_114_537_876_8,
|
|
96
|
-
186_056.265_395_223_495_040_294_989_716_045_699_282_207_842_363_28,
|
|
97
|
-
8071.672_002_365_816_210_638_002_902_272_250_613_821_851_632_502_4,
|
|
98
|
-
210.824_277_751_579_345_872_509_733_920_713_362_711_669_695_802_91,
|
|
99
|
-
2.506_628_274_631_000_270_164_908_177_133_837_338_626_431_079_340_8,
|
|
87
|
+
23_531_376_880.41075968857200767445163675473484680494, 42_919_803_642.649098768957899047001988850926355848959,
|
|
88
|
+
35_711_959_237.355668049440185451547166705960488635843, 17_921_034_426.03720969991975575445893111267140326539,
|
|
89
|
+
6_039_542_586.3520280050642916443072979210699388420708, 1_439_720_407.3117216736632230727949123939715485786772,
|
|
90
|
+
248_874_557.86205415651146038641322942321632125127801, 31_426_415.58540019438061423162831820536287468498764,
|
|
91
|
+
2_876_370.6289353724412254090516208496135991145378768, 186_056.26539522349504029498971604569928220784236328,
|
|
92
|
+
8071.6720023658162106380029022722506138218516325024, 210.82427775157934587250973392071336271166969580291,
|
|
93
|
+
2.5066282746310002701649081771338373386264310793408,
|
|
100
94
|
] as const;
|
|
101
95
|
|
|
102
96
|
const SDEN = [
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toBoolean } from '../../../../helpers/convert/
|
|
1
|
+
import { toBoolean } from '../../../../helpers/convert/index.js';
|
|
2
2
|
import { entries } from '../../../../helpers/utils.js';
|
|
3
3
|
import { Cp } from '../../../checkpoint.js';
|
|
4
4
|
import { $Call } from '../../../operations/index.js';
|
|
@@ -56,8 +56,13 @@ export const entries = VmLib(
|
|
|
56
56
|
arr.push({ 0: i, 1: data[i] ?? null });
|
|
57
57
|
}
|
|
58
58
|
return arr;
|
|
59
|
+
} else {
|
|
60
|
+
const arr: Array<{ 0: string; 1: VmConst }> = [];
|
|
61
|
+
for (const [key, value] of _entries(data)) {
|
|
62
|
+
arr.push({ 0: key, 1: value ?? null });
|
|
63
|
+
}
|
|
64
|
+
return arr;
|
|
59
65
|
}
|
|
60
|
-
return _entries(data).map(([key, value]) => ({ 0: key, 1: value ?? null }));
|
|
61
66
|
},
|
|
62
67
|
{
|
|
63
68
|
summary: '返回数组或记录的键值对列表',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toBoolean } from '../../../../helpers/convert/
|
|
1
|
+
import { toBoolean } from '../../../../helpers/convert/index.js';
|
|
2
2
|
import { entries } from '../../../../helpers/utils.js';
|
|
3
3
|
import { Cp } from '../../../checkpoint.js';
|
|
4
4
|
import { $Call, $Same } from '../../../operations/index.js';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { $Call } from '../../../operations/index.js';
|
|
2
|
+
import type { VmValue } from '../../../types/index.js';
|
|
3
|
+
import { VmLib, expectCallable, expectConst, iterate, required } from '../../helpers.js';
|
|
4
|
+
|
|
5
|
+
export const fold = VmLib(
|
|
6
|
+
(data, initial, f) => {
|
|
7
|
+
required('initial', initial, null);
|
|
8
|
+
expectConst('data', data, null);
|
|
9
|
+
expectCallable('f', f, data);
|
|
10
|
+
|
|
11
|
+
let acc: VmValue = initial;
|
|
12
|
+
iterate(data, (value, index, data) => {
|
|
13
|
+
acc = $Call(f, [acc, value, index, data]);
|
|
14
|
+
});
|
|
15
|
+
return acc;
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
summary: '对数组或记录中的每个元素应用函数,并返回累积结果',
|
|
19
|
+
params: {
|
|
20
|
+
data: { type: 'array | record', description: '要折叠的数组或记录' },
|
|
21
|
+
initial: { type: 'any', description: '初始累积值' },
|
|
22
|
+
f: {
|
|
23
|
+
type: 'fn(acc: type(initial), value: any, key: number | string, input: type(data)) -> type(initial)',
|
|
24
|
+
description: '应用于每个元素的函数',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
returns: { type: 'type(initial)' },
|
|
28
|
+
examples: ['fold([1, 2, 3], 0, fn (acc, x) { acc + x }) // 6'],
|
|
29
|
+
},
|
|
30
|
+
);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { toString } from '../../../../helpers/convert/index.js';
|
|
2
|
+
import { fromEntries } from '../../../../helpers/utils.js';
|
|
3
|
+
import { $Call } from '../../../operations/call.js';
|
|
4
|
+
import type { VmConst } from '../../../types/index.js';
|
|
5
|
+
import { VmLib, expectArray, expectCallable } from '../../helpers.js';
|
|
6
|
+
|
|
7
|
+
export const group_by = VmLib(
|
|
8
|
+
(data, key) => {
|
|
9
|
+
expectArray('data', data, null);
|
|
10
|
+
expectCallable('key', key, data);
|
|
11
|
+
const result = new Map<string, VmConst[]>();
|
|
12
|
+
const len = data.length;
|
|
13
|
+
for (let i = 0; i < len; i++) {
|
|
14
|
+
const v = data[i] ?? null;
|
|
15
|
+
const k = toString($Call(key, [v, i, data]), undefined);
|
|
16
|
+
let arr = result.get(k);
|
|
17
|
+
if (!arr) {
|
|
18
|
+
arr = [];
|
|
19
|
+
result.set(k, arr);
|
|
20
|
+
}
|
|
21
|
+
arr.push(v);
|
|
22
|
+
}
|
|
23
|
+
return fromEntries(result);
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
summary: '根据指定的键函数对数组进行分组',
|
|
27
|
+
params: {
|
|
28
|
+
data: { type: 'array', description: '要分组的数组' },
|
|
29
|
+
key: {
|
|
30
|
+
type: 'fn(value: any, index: number, arr: type(data)) -> string',
|
|
31
|
+
description: '用于生成分组键的函数',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
returns: { type: 'record' },
|
|
35
|
+
examples: ['group_by([1, 2, 3, 4], fn { it % 2 }) // ("0": [2, 4], "1": [1, 3])'],
|
|
36
|
+
},
|
|
37
|
+
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { toBoolean } from '../../../../helpers/convert/
|
|
1
|
+
import { toBoolean } from '../../../../helpers/convert/index.js';
|
|
2
2
|
import { $Call } from '../../../operations/index.js';
|
|
3
3
|
import { isVmConst, type VmAny, type VmValue } from '../../../types/index.js';
|
|
4
|
-
import { VmLib, expectCallable, expectConst,
|
|
4
|
+
import { VmLib, expectCallable, expectConst, iterate } from '../../helpers.js';
|
|
5
5
|
|
|
6
6
|
export * from './with.js';
|
|
7
7
|
export * from './entries.js';
|
|
@@ -16,7 +16,7 @@ function mapImplWrapped(
|
|
|
16
16
|
): VmValue {
|
|
17
17
|
expectConst('data', data, null);
|
|
18
18
|
expectCallable(fnName, fn, data);
|
|
19
|
-
return
|
|
19
|
+
return iterate(data, (value, index, data) => {
|
|
20
20
|
const ret = mapper(fn, value, index, data);
|
|
21
21
|
if (ret === undefined || isVmConst(ret)) return ret;
|
|
22
22
|
return null;
|