@mirascript/mirascript 0.1.15 → 0.1.17

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.
Files changed (229) hide show
  1. package/dist/chunk-JG3D67GF.js +1625 -0
  2. package/dist/chunk-JG3D67GF.js.map +6 -0
  3. package/dist/chunk-RIT53WVY.js +1 -0
  4. package/dist/chunk-RLWIIOH5.js +12 -0
  5. package/dist/chunk-RLWIIOH5.js.map +6 -0
  6. package/dist/{chunk-NT235HY3.js → chunk-W2I5XPIE.js} +1490 -608
  7. package/dist/chunk-W2I5XPIE.js.map +6 -0
  8. package/dist/cli/index.js +11 -67
  9. package/dist/cli/index.js.map +2 -2
  10. package/dist/compiler/compile-fast.d.ts +1 -1
  11. package/dist/compiler/compile-fast.d.ts.map +1 -1
  12. package/dist/compiler/create-script.d.ts +10 -1
  13. package/dist/compiler/create-script.d.ts.map +1 -1
  14. package/dist/compiler/diagnostic.d.ts +1 -1
  15. package/dist/compiler/diagnostic.d.ts.map +1 -1
  16. package/dist/compiler/emit/constants.d.ts +3 -0
  17. package/dist/compiler/emit/constants.d.ts.map +1 -0
  18. package/dist/compiler/emit/consts.d.ts +6 -0
  19. package/dist/compiler/emit/consts.d.ts.map +1 -0
  20. package/dist/compiler/emit/globals.d.ts +17 -0
  21. package/dist/compiler/emit/globals.d.ts.map +1 -0
  22. package/dist/compiler/emit/index.d.ts +58 -0
  23. package/dist/compiler/emit/index.d.ts.map +1 -0
  24. package/dist/compiler/emit/sourcemap.d.ts +6 -0
  25. package/dist/compiler/emit/sourcemap.d.ts.map +1 -0
  26. package/dist/compiler/index.d.ts +3 -2
  27. package/dist/compiler/index.d.ts.map +1 -1
  28. package/dist/compiler/worker.js +1 -1
  29. package/dist/helpers/constants.d.ts +10 -0
  30. package/dist/helpers/constants.d.ts.map +1 -1
  31. package/dist/helpers/convert/index.d.ts +5 -0
  32. package/dist/helpers/convert/index.d.ts.map +1 -0
  33. package/dist/helpers/convert/to-boolean.d.ts +4 -0
  34. package/dist/helpers/convert/to-boolean.d.ts.map +1 -0
  35. package/dist/helpers/convert/to-format.d.ts +4 -0
  36. package/dist/helpers/convert/to-format.d.ts.map +1 -0
  37. package/dist/helpers/convert/to-number.d.ts +4 -0
  38. package/dist/helpers/convert/to-number.d.ts.map +1 -0
  39. package/dist/helpers/convert/to-string.d.ts +6 -0
  40. package/dist/helpers/convert/to-string.d.ts.map +1 -0
  41. package/dist/{vm → helpers}/error.d.ts +1 -1
  42. package/dist/helpers/error.d.ts.map +1 -0
  43. package/dist/helpers/serialize.d.ts +13 -4
  44. package/dist/helpers/serialize.d.ts.map +1 -1
  45. package/dist/helpers/types.d.ts +54 -0
  46. package/dist/helpers/types.d.ts.map +1 -0
  47. package/dist/index.js +11 -17
  48. package/dist/subtle.d.ts +4 -3
  49. package/dist/subtle.d.ts.map +1 -1
  50. package/dist/subtle.js +20 -16
  51. package/dist/vm/checkpoint.d.ts +9 -0
  52. package/dist/vm/checkpoint.d.ts.map +1 -0
  53. package/dist/vm/helpers.d.ts +4 -10
  54. package/dist/vm/helpers.d.ts.map +1 -1
  55. package/dist/vm/index.d.ts +3 -3
  56. package/dist/vm/index.d.ts.map +1 -1
  57. package/dist/vm/lib/global/bit.d.ts +7 -7
  58. package/dist/vm/lib/global/bit.d.ts.map +1 -1
  59. package/dist/vm/lib/global/debug.d.ts +2 -2
  60. package/dist/vm/lib/global/debug.d.ts.map +1 -1
  61. package/dist/vm/lib/global/index.d.ts +0 -1
  62. package/dist/vm/lib/global/index.d.ts.map +1 -1
  63. package/dist/vm/lib/global/json.d.ts +2 -2
  64. package/dist/vm/lib/global/json.d.ts.map +1 -1
  65. package/dist/vm/lib/global/math-additional.d.ts +1 -1
  66. package/dist/vm/lib/global/math-additional.d.ts.map +1 -1
  67. package/dist/vm/lib/global/math-arr.d.ts +5 -5
  68. package/dist/vm/lib/global/math-arr.d.ts.map +1 -1
  69. package/dist/vm/lib/global/math-unary.d.ts +26 -26
  70. package/dist/vm/lib/global/math-unary.d.ts.map +1 -1
  71. package/dist/vm/lib/global/math.d.ts +3 -3
  72. package/dist/vm/lib/global/math.d.ts.map +1 -1
  73. package/dist/vm/lib/global/sequence/all-any.d.ts +2 -2
  74. package/dist/vm/lib/global/sequence/all-any.d.ts.map +1 -1
  75. package/dist/vm/lib/global/sequence/entries.d.ts +5 -5
  76. package/dist/vm/lib/global/sequence/entries.d.ts.map +1 -1
  77. package/dist/vm/lib/global/sequence/find.d.ts +3 -3
  78. package/dist/vm/lib/global/sequence/find.d.ts.map +1 -1
  79. package/dist/vm/lib/global/sequence/flatten.d.ts +1 -1
  80. package/dist/vm/lib/global/sequence/flatten.d.ts.map +1 -1
  81. package/dist/vm/lib/global/sequence/len.d.ts +1 -1
  82. package/dist/vm/lib/global/sequence/len.d.ts.map +1 -1
  83. package/dist/vm/lib/global/sequence/map-filter.d.ts +3 -3
  84. package/dist/vm/lib/global/sequence/map-filter.d.ts.map +1 -1
  85. package/dist/vm/lib/global/sequence/repeat.d.ts +1 -1
  86. package/dist/vm/lib/global/sequence/repeat.d.ts.map +1 -1
  87. package/dist/vm/lib/global/sequence/reverse.d.ts +1 -1
  88. package/dist/vm/lib/global/sequence/reverse.d.ts.map +1 -1
  89. package/dist/vm/lib/global/sequence/sort.d.ts +2 -2
  90. package/dist/vm/lib/global/sequence/sort.d.ts.map +1 -1
  91. package/dist/vm/lib/global/sequence/with.d.ts +2 -2
  92. package/dist/vm/lib/global/sequence/with.d.ts.map +1 -1
  93. package/dist/vm/lib/global/sequence/zip.d.ts +1 -1
  94. package/dist/vm/lib/global/sequence/zip.d.ts.map +1 -1
  95. package/dist/vm/lib/global/string.d.ts +10 -10
  96. package/dist/vm/lib/global/string.d.ts.map +1 -1
  97. package/dist/vm/lib/global/time.d.ts +3 -13
  98. package/dist/vm/lib/global/time.d.ts.map +1 -1
  99. package/dist/vm/lib/global/to-primitive.d.ts +4 -4
  100. package/dist/vm/lib/global/to-primitive.d.ts.map +1 -1
  101. package/dist/vm/lib/helpers.d.ts +53 -0
  102. package/dist/vm/lib/helpers.d.ts.map +1 -0
  103. package/dist/vm/lib/index.d.ts +4 -0
  104. package/dist/vm/lib/index.d.ts.map +1 -0
  105. package/dist/vm/lib/{_loader.d.ts → loader.d.ts} +5 -5
  106. package/dist/vm/lib/loader.d.ts.map +1 -0
  107. package/dist/vm/lib/mod/index.d.ts +2 -0
  108. package/dist/vm/lib/mod/index.d.ts.map +1 -0
  109. package/dist/vm/lib/mod/matrix.d.ts +15 -0
  110. package/dist/vm/lib/mod/matrix.d.ts.map +1 -0
  111. package/dist/vm/operations.d.ts +2 -4
  112. package/dist/vm/operations.d.ts.map +1 -1
  113. package/dist/vm/types/boundary.d.ts +1 -1
  114. package/dist/vm/types/boundary.d.ts.map +1 -1
  115. package/dist/vm/types/context.d.ts +4 -17
  116. package/dist/vm/types/context.d.ts.map +1 -1
  117. package/dist/vm/types/extern.d.ts +1 -3
  118. package/dist/vm/types/extern.d.ts.map +1 -1
  119. package/dist/vm/types/function.d.ts +1 -6
  120. package/dist/vm/types/function.d.ts.map +1 -1
  121. package/dist/vm/types/index.d.ts +31 -17
  122. package/dist/vm/types/index.d.ts.map +1 -1
  123. package/dist/vm/types/module.d.ts +2 -4
  124. package/dist/vm/types/module.d.ts.map +1 -1
  125. package/dist/vm/types/wrapper.d.ts +0 -2
  126. package/dist/vm/types/wrapper.d.ts.map +1 -1
  127. package/package.json +7 -3
  128. package/src/cli/index.ts +1 -1
  129. package/src/compiler/compile-fast.ts +1 -2
  130. package/src/compiler/create-script.ts +12 -2
  131. package/src/compiler/diagnostic.ts +17 -8
  132. package/src/compiler/emit/constants.ts +2 -0
  133. package/src/compiler/emit/consts.ts +47 -0
  134. package/src/compiler/emit/globals.ts +39 -0
  135. package/src/compiler/{emit.ts → emit/index.ts} +16 -200
  136. package/src/compiler/emit/sourcemap.ts +168 -0
  137. package/src/compiler/index.ts +9 -9
  138. package/src/compiler/worker.ts +1 -1
  139. package/src/helpers/constants.ts +12 -0
  140. package/src/helpers/convert/index.ts +4 -0
  141. package/src/helpers/convert/to-boolean.ts +12 -0
  142. package/src/helpers/convert/to-format.ts +37 -0
  143. package/src/helpers/convert/to-number.ts +35 -0
  144. package/src/helpers/convert/to-string.ts +55 -0
  145. package/src/{vm → helpers}/error.ts +1 -1
  146. package/src/helpers/serialize.ts +72 -24
  147. package/src/helpers/types.ts +267 -0
  148. package/src/subtle.ts +4 -2
  149. package/src/vm/checkpoint.ts +42 -0
  150. package/src/vm/helpers.ts +9 -53
  151. package/src/vm/index.ts +3 -3
  152. package/src/vm/lib/global/bit.ts +8 -9
  153. package/src/vm/lib/global/debug.ts +5 -4
  154. package/src/vm/lib/global/index.ts +0 -1
  155. package/src/vm/lib/global/json.ts +2 -2
  156. package/src/vm/lib/global/math-additional.ts +2 -4
  157. package/src/vm/lib/global/math-arr.ts +1 -1
  158. package/src/vm/lib/global/math-unary.ts +2 -4
  159. package/src/vm/lib/global/math.ts +3 -4
  160. package/src/vm/lib/global/sequence/all-any.ts +11 -6
  161. package/src/vm/lib/global/sequence/entries.ts +1 -1
  162. package/src/vm/lib/global/sequence/find.ts +4 -3
  163. package/src/vm/lib/global/sequence/flatten.ts +2 -3
  164. package/src/vm/lib/global/sequence/len.ts +1 -1
  165. package/src/vm/lib/global/sequence/map-filter.ts +4 -3
  166. package/src/vm/lib/global/sequence/repeat.ts +2 -4
  167. package/src/vm/lib/global/sequence/reverse.ts +1 -1
  168. package/src/vm/lib/global/sequence/sort.ts +6 -5
  169. package/src/vm/lib/global/sequence/with.ts +21 -20
  170. package/src/vm/lib/global/sequence/zip.ts +3 -3
  171. package/src/vm/lib/global/string.ts +16 -27
  172. package/src/vm/lib/global/time.ts +59 -30
  173. package/src/vm/lib/global/to-primitive.ts +27 -18
  174. package/src/vm/lib/{_helpers.ts → helpers.ts} +132 -44
  175. package/src/vm/lib/index.ts +16 -0
  176. package/src/vm/lib/{_loader.ts → loader.ts} +3 -11
  177. package/src/vm/lib/mod/index.ts +1 -0
  178. package/src/vm/lib/{global/mod → mod}/matrix.ts +9 -7
  179. package/src/vm/operations.ts +41 -137
  180. package/src/vm/types/boundary.ts +10 -13
  181. package/src/vm/types/context.ts +31 -50
  182. package/src/vm/types/extern.ts +8 -15
  183. package/src/vm/types/function.ts +4 -19
  184. package/src/vm/types/index.ts +47 -25
  185. package/src/vm/types/module.ts +3 -7
  186. package/src/vm/types/wrapper.ts +1 -5
  187. package/dist/chunk-35JGBXRE.js +0 -1
  188. package/dist/chunk-JVFUK7AN.js +0 -2324
  189. package/dist/chunk-JVFUK7AN.js.map +0 -6
  190. package/dist/chunk-NT235HY3.js.map +0 -6
  191. package/dist/compiler/emit.d.ts +0 -5
  192. package/dist/compiler/emit.d.ts.map +0 -1
  193. package/dist/vm/error.d.ts.map +0 -1
  194. package/dist/vm/lib/_helpers.d.ts +0 -35
  195. package/dist/vm/lib/_helpers.d.ts.map +0 -1
  196. package/dist/vm/lib/_loader.d.ts.map +0 -1
  197. package/dist/vm/lib/global/mod/index.d.ts +0 -3
  198. package/dist/vm/lib/global/mod/index.d.ts.map +0 -1
  199. package/dist/vm/lib/global/mod/matrix.d.ts +0 -15
  200. package/dist/vm/lib/global/mod/matrix.d.ts.map +0 -1
  201. package/dist/vm/types/any.d.ts +0 -10
  202. package/dist/vm/types/any.d.ts.map +0 -1
  203. package/dist/vm/types/array.d.ts +0 -12
  204. package/dist/vm/types/array.d.ts.map +0 -1
  205. package/dist/vm/types/callable.d.ts +0 -5
  206. package/dist/vm/types/callable.d.ts.map +0 -1
  207. package/dist/vm/types/const.d.ts +0 -15
  208. package/dist/vm/types/const.d.ts.map +0 -1
  209. package/dist/vm/types/immutable.d.ts +0 -15
  210. package/dist/vm/types/immutable.d.ts.map +0 -1
  211. package/dist/vm/types/primitive.d.ts +0 -7
  212. package/dist/vm/types/primitive.d.ts.map +0 -1
  213. package/dist/vm/types/record.d.ts +0 -20
  214. package/dist/vm/types/record.d.ts.map +0 -1
  215. package/dist/vm/types/script.d.ts +0 -14
  216. package/dist/vm/types/script.d.ts.map +0 -1
  217. package/dist/vm/types/value.d.ts +0 -14
  218. package/dist/vm/types/value.d.ts.map +0 -1
  219. package/src/vm/lib/global/mod/index.ts +0 -4
  220. package/src/vm/types/any.ts +0 -33
  221. package/src/vm/types/array.ts +0 -19
  222. package/src/vm/types/callable.ts +0 -10
  223. package/src/vm/types/const.ts +0 -109
  224. package/src/vm/types/immutable.ts +0 -22
  225. package/src/vm/types/primitive.ts +0 -14
  226. package/src/vm/types/record.ts +0 -53
  227. package/src/vm/types/script.ts +0 -18
  228. package/src/vm/types/value.ts +0 -22
  229. /package/dist/{chunk-35JGBXRE.js.map → chunk-RIT53WVY.js.map} +0 -0
@@ -1,10 +1,8 @@
1
- import { $ToString } from '../../operations.js';
2
- import { expectArray, required, VmLib } from '../_helpers.js';
1
+ import { expectArray, expectString, VmLib } from '../helpers.js';
3
2
 
4
3
  export const chars = VmLib(
5
4
  (str) => {
6
- required('str', str, null);
7
- return [...$ToString(str)];
5
+ return [...expectString('str', str)];
8
6
  },
9
7
  {
10
8
  summary: '将字符串转换为字符数组',
@@ -17,9 +15,7 @@ export const chars = VmLib(
17
15
 
18
16
  export const starts_with = VmLib(
19
17
  (str, search) => {
20
- required('str', str, null);
21
- required('search', search, null);
22
- return $ToString(str).startsWith($ToString(search));
18
+ return expectString('str', str).startsWith(expectString('search', search));
23
19
  },
24
20
  {
25
21
  summary: '检查字符串是否以指定子串开头',
@@ -31,9 +27,7 @@ export const starts_with = VmLib(
31
27
  );
32
28
  export const ends_with = VmLib(
33
29
  (str, search) => {
34
- required('str', str, null);
35
- required('search', search, null);
36
- return $ToString(str).endsWith($ToString(search));
30
+ return expectString('str', str).endsWith(expectString('search', search));
37
31
  },
38
32
  {
39
33
  summary: '检查字符串是否以指定子串结尾',
@@ -46,9 +40,7 @@ export const ends_with = VmLib(
46
40
 
47
41
  export const contains = VmLib(
48
42
  (str, search) => {
49
- required('str', str, null);
50
- required('search', search, null);
51
- return $ToString(str).includes($ToString(search));
43
+ return expectString('str', str).includes(expectString('search', search));
52
44
  },
53
45
  {
54
46
  summary: '检查字符串是否包含指定子串',
@@ -61,8 +53,7 @@ export const contains = VmLib(
61
53
 
62
54
  export const trim_start = VmLib(
63
55
  (str) => {
64
- required('str', str, null);
65
- return $ToString(str).trimStart();
56
+ return expectString('str', str).trimStart();
66
57
  },
67
58
  {
68
59
  summary: '去除字符串开头的空白字符',
@@ -75,8 +66,7 @@ export const trim_start = VmLib(
75
66
 
76
67
  export const trim_end = VmLib(
77
68
  (str) => {
78
- required('str', str, null);
79
- return $ToString(str).trimEnd();
69
+ return expectString('str', str).trimEnd();
80
70
  },
81
71
  {
82
72
  summary: '去除字符串结尾的空白字符',
@@ -89,8 +79,7 @@ export const trim_end = VmLib(
89
79
 
90
80
  export const trim = VmLib(
91
81
  (str) => {
92
- required('str', str, null);
93
- return $ToString(str).trim();
82
+ return expectString('str', str).trim();
94
83
  },
95
84
  {
96
85
  summary: '去除字符串两端的空白字符',
@@ -103,9 +92,10 @@ export const trim = VmLib(
103
92
 
104
93
  export const replace = VmLib(
105
94
  (str, search, replacement = '') => {
106
- required('str', str, null);
107
- required('search', search, str);
108
- return $ToString(str).replaceAll($ToString(search), $ToString(replacement));
95
+ return expectString('str', str).replaceAll(
96
+ expectString('search', search),
97
+ expectString('replacement', replacement),
98
+ );
109
99
  },
110
100
  {
111
101
  summary: '替换字符串中的指定子串',
@@ -118,9 +108,8 @@ export const replace = VmLib(
118
108
 
119
109
  export const split = VmLib(
120
110
  (str, separator = '') => {
121
- required('str', str, null);
122
- const s = $ToString(str);
123
- const p = $ToString(separator);
111
+ const s = expectString('str', str);
112
+ const p = expectString('separator', separator);
124
113
  if (!p) return [...s];
125
114
  return s.split(p);
126
115
  },
@@ -136,8 +125,8 @@ export const split = VmLib(
136
125
  export const join = VmLib(
137
126
  (arr, separator = '') => {
138
127
  expectArray('arr', arr, null);
139
- const s = $ToString(separator);
140
- return arr.map((v) => $ToString(v)).join(s);
128
+ const s = expectString('separator', separator);
129
+ return arr.map((v) => expectString(null, v)).join(s);
141
130
  },
142
131
  {
143
132
  summary: '将字符串数组连接为单个字符串',
@@ -1,35 +1,60 @@
1
- import { $ToString, $ToNumber } from '../../operations.js';
2
- import { VmLib } from '../_helpers.js';
3
- import { isFinite } from '../../../helpers/utils.js';
1
+ import { describeParam, expectNumberRange, throwError, throwUnexpectedTypeError, VmLib } from '../helpers.js';
2
+ import { isNaN, isFinite } from '../../../helpers/utils.js';
3
+ import { toNumber } from '../../../helpers/convert/to-number.js';
4
+ import { display } from '../../../helpers/serialize.js';
5
+ import type { VmAny } from '../../types/index.js';
6
+
7
+ const fromNumber = (datetime: number, fallback: boolean): number | null => {
8
+ const n = new Date(datetime).getTime();
9
+ if (isFinite(n)) return n;
10
+ if (fallback) return null;
11
+ throwError(`${describeParam('datetime')} is an invalid timestamp: ${display(datetime)}`, Number.NaN);
12
+ };
13
+
14
+ const getTimestamp = (datetime: VmAny, fallback: boolean): number | null => {
15
+ if (datetime == null) {
16
+ return Date.now();
17
+ }
18
+ if (typeof datetime == 'number') {
19
+ return fromNumber(datetime, fallback);
20
+ }
21
+ if (typeof datetime != 'string') {
22
+ if (fallback) return null;
23
+ throwUnexpectedTypeError('datetime', 'number | string', datetime, Number.NaN);
24
+ }
25
+ const num = toNumber(datetime, Number.NaN);
26
+ if (!isNaN(num)) {
27
+ return fromNumber(num, fallback);
28
+ }
29
+ const parsed = Date.parse(datetime);
30
+ if (isFinite(parsed)) return parsed;
31
+ if (fallback) return null;
32
+ throwError(`${describeParam('datetime')} cannot be parsed as datetime: ${display(datetime)}`, Number.NaN);
33
+ };
4
34
 
5
35
  export const to_timestamp = VmLib(
6
- (datetime) => {
7
- if (datetime == null) {
8
- return Date.now();
9
- }
10
- if (typeof datetime == 'number') {
11
- return new Date(datetime).getTime();
12
- }
13
- const str = $ToString(datetime);
14
- if (!str) return Number.NaN;
15
- const num = $ToNumber(str);
16
- if (isFinite(num)) return num;
17
- return Date.parse(str);
36
+ (datetime, fallback) => {
37
+ const timestamp = getTimestamp(datetime, fallback !== undefined);
38
+ if (timestamp == null) return fallback;
39
+ return timestamp;
18
40
  },
19
41
  {
20
42
  summary: '将数据转换为 Unix 毫秒时间戳',
21
- params: { datetime: '要转换的数据,默认为当前时间' },
22
- paramsType: { datetime: 'number | string' },
23
- returnsType: 'number',
43
+ params: {
44
+ datetime: '要转换的数据,默认为当前时间',
45
+ fallback: '转换失败时的返回值',
46
+ },
47
+ paramsType: { datetime: 'number | string', fallback: 'any' },
48
+ returnsType: 'number | type(fallback)',
24
49
  examples: ['to_timestamp("1970-01-01T00:00:00Z") // 0'],
25
50
  },
26
51
  );
27
52
 
28
53
  export const to_datetime = VmLib(
29
- (datetime, offset) => {
30
- const timestamp = to_timestamp(datetime);
31
- if (!isFinite(timestamp)) return null;
32
- const o = $ToNumber(offset ?? 0) || 0;
54
+ (datetime, offset, fallback) => {
55
+ const timestamp = getTimestamp(datetime, fallback !== undefined);
56
+ if (timestamp == null) return fallback;
57
+ const o = expectNumberRange('offset', offset ?? 0, -24, 24);
33
58
  const dateOffset = new Date(timestamp + o * 1000 * 60 * 60);
34
59
  return {
35
60
  year: dateOffset.getUTCFullYear(),
@@ -48,9 +73,10 @@ export const to_datetime = VmLib(
48
73
  params: {
49
74
  datetime: '要转换的数据,默认为当前时间',
50
75
  offset: '时区偏移量(单位:小时),默认为 0',
76
+ fallback: '转换失败时的返回值',
51
77
  },
52
- paramsType: { datetime: 'number | string', offset: 'number' },
53
- returnsType: 'Date',
78
+ paramsType: { datetime: 'number | string', offset: 'number', fallback: 'any' },
79
+ returnsType: 'Date | type(fallback)',
54
80
  examples: [
55
81
  `
56
82
  to_datetime(0)
@@ -65,16 +91,19 @@ to_datetime(0)
65
91
  );
66
92
 
67
93
  export const to_iso8601 = VmLib(
68
- (datetime) => {
69
- const timestamp = to_timestamp(datetime);
70
- if (!isFinite(timestamp)) return null;
94
+ (datetime, fallback) => {
95
+ const timestamp = getTimestamp(datetime, fallback !== undefined);
96
+ if (timestamp == null) return fallback;
71
97
  return new Date(timestamp).toISOString();
72
98
  },
73
99
  {
74
100
  summary: '将数据转换为 ISO 8601 格式的字符串',
75
- params: { datetime: '要转换的数据,默认为当前时间' },
76
- paramsType: { datetime: 'number | string' },
77
- returnsType: 'string',
101
+ params: {
102
+ datetime: '要转换的数据,默认为当前时间',
103
+ fallback: '转换失败时的返回值',
104
+ },
105
+ paramsType: { datetime: 'number | string', fallback: 'any' },
106
+ returnsType: 'string | type(fallback)',
78
107
  examples: ['to_iso8601(0) // "1970-01-01T00:00:00.000Z"'],
79
108
  },
80
109
  );
@@ -1,44 +1,53 @@
1
- import { $ToString, $ToNumber, $ToBoolean, $Format } from '../../operations.js';
2
- import { required, VmLib } from '../_helpers.js';
1
+ import { toBoolean, toFormat, toNumber, toString } from '../../../helpers/convert/index.js';
2
+ import { expectString, required, VmLib } from '../helpers.js';
3
3
 
4
4
  export const to_string = VmLib(
5
- (data) => {
5
+ (data, fallback) => {
6
6
  required('data', data, '');
7
- return $ToString(data);
7
+ return toString(data, fallback);
8
8
  },
9
9
  {
10
10
  summary: '将数据转换为字符串',
11
- params: { data: '要转换的数据' },
12
- paramsType: { data: 'any' },
13
- returnsType: 'string',
11
+ params: {
12
+ data: '要转换的数据',
13
+ fallback: '转换失败时的返回值',
14
+ },
15
+ paramsType: { data: 'any', fallback: 'any' },
16
+ returnsType: 'string | type(fallback)',
14
17
  examples: ['to_string([1, 2]) // "1, 2"'],
15
18
  },
16
19
  );
17
20
 
18
21
  export const to_number = VmLib(
19
- (data) => {
22
+ (data, fallback) => {
20
23
  required('data', data, Number.NaN);
21
- return $ToNumber(data);
24
+ return toNumber(data, fallback);
22
25
  },
23
26
  {
24
27
  summary: '将数据转换为数字',
25
- params: { data: '要转换的数据' },
26
- paramsType: { data: 'any' },
27
- returnsType: 'number',
28
+ params: {
29
+ data: '要转换的数据',
30
+ fallback: '转换失败时的返回值',
31
+ },
32
+ paramsType: { data: 'any', fallback: 'any' },
33
+ returnsType: 'number | type(fallback)',
28
34
  examples: ['to_number("1.5") // 1.5'],
29
35
  },
30
36
  );
31
37
 
32
38
  export const to_boolean = VmLib(
33
- (data) => {
39
+ (data, fallback) => {
34
40
  required('data', data, false);
35
- return $ToBoolean(data);
41
+ return toBoolean(data, fallback);
36
42
  },
37
43
  {
38
44
  summary: '将数据转换为布尔值',
39
- params: { data: '要转换的数据' },
40
- paramsType: { data: 'any' },
41
- returnsType: 'boolean',
45
+ params: {
46
+ data: '要转换的数据',
47
+ fallback: '转换失败时的返回值',
48
+ },
49
+ paramsType: { data: 'any', fallback: 'any' },
50
+ returnsType: 'boolean | type(fallback)',
42
51
  examples: ['to_boolean(nil) // false'],
43
52
  },
44
53
  );
@@ -46,7 +55,7 @@ export const to_boolean = VmLib(
46
55
  export const format = VmLib(
47
56
  (data, format) => {
48
57
  required('data', data, '');
49
- return $Format(data, format);
58
+ return toFormat(data, expectString('format', format));
50
59
  },
51
60
  {
52
61
  summary: '将数据格式化为指定格式的字符串',
@@ -1,44 +1,59 @@
1
1
  import type { Writable } from 'type-fest';
2
- import { VmError } from '../error.js';
3
- import { $ToNumber, $Type } from '../operations.js';
4
- import {
5
- isVmArray,
6
- isVmFunction,
7
- type VmExtern,
8
- type VmFunction,
9
- type VmAny,
10
- type VmArray,
11
- type VmValue,
12
- isVmRecord,
13
- type VmRecord,
14
- type VmModule,
15
- isVmPrimitive,
16
- type VmConst,
17
- isVmConst,
18
- VM_ARRAY_MAX_LENGTH,
19
- isVmCallable,
2
+ import { VM_ARRAY_MAX_LENGTH } from '../../helpers/constants.js';
3
+ import { isNaN, entries, fromEntries, isSafeInteger, isFinite } from '../../helpers/utils.js';
4
+ import { toBoolean, toNumber, toString } from '../../helpers/convert/index.js';
5
+ import { display } from '../../helpers/serialize.js';
6
+ import { isVmArray, isVmFunction, isVmPrimitive, isVmConst, isVmCallable, isVmRecord } from '../../helpers/types.js';
7
+ import { VmError } from '../../helpers/error.js';
8
+ import type {
9
+ VmExtern,
10
+ VmFunction,
11
+ VmAny,
12
+ VmArray,
13
+ VmValue,
14
+ VmRecord,
15
+ VmModule,
16
+ VmConst,
17
+ VmFunctionLike,
18
+ VmFunctionOption,
20
19
  } from '../types/index.js';
21
- import type { VmFunctionLike, VmFunctionOption } from '../types/function.js';
22
20
  import { Cp } from '../helpers.js';
23
- import { isNaN, entries, fromEntries } from '../../helpers/utils.js';
24
21
 
25
22
  /** 抛出异常 */
26
23
  export function throwError(message: string, recovered: VmAny | (() => VmAny)): never {
27
24
  const recoveredValue = typeof recovered === 'function' && !isVmFunction(recovered) ? recovered() : recovered;
28
25
  throw new VmError(message, recoveredValue);
29
26
  }
27
+ /** 描述参数 */
28
+ type ParamIndex = number | string | null;
29
+ /** 描述参数 */
30
+ export function describeParam(name: ParamIndex): string {
31
+ if (name == null) return 'Value';
32
+ if (typeof name == 'string') {
33
+ if (!name) return 'Argument';
34
+ return `Argument '${name}'`;
35
+ }
36
+ const pos = name <= 0 ? 'first' : name <= 1 ? 'second' : `${name + 1}th`;
37
+ return `Argument at the ${pos} position`;
38
+ }
30
39
 
31
40
  /** 抛出预期外类型异常 */
32
41
  export function throwUnexpectedTypeError(
33
- name: number | string,
42
+ name: ParamIndex,
43
+ expected: string,
44
+ value: VmAny,
45
+ recovered: VmAny | (() => VmAny),
46
+ ): never {
47
+ throwError(`${describeParam(name)} is not ${expected}: ${display(value)}`, recovered);
48
+ }
49
+ /** 抛出预期外类型异常 */
50
+ export function throwUnconvertedTypeError(
51
+ name: ParamIndex,
34
52
  expected: string,
35
53
  value: VmAny,
36
54
  recovered: VmAny | (() => VmAny),
37
55
  ): never {
38
- const actual = $Type(value);
39
- if (typeof name == 'string') throwError(`Expected ${expected} for parameter '${name}', got ${actual}`, recovered);
40
- const pos = name <= 0 ? 'first' : name <= 1 ? 'second' : name + 1 + 'th';
41
- throwError(`Expected ${expected} at the ${pos} position, got ${actual}`, recovered);
56
+ throwError(`${describeParam(name)} cannot be converted to ${expected}: ${display(value)}`, recovered);
42
57
  }
43
58
 
44
59
  /** 重新抛出异常 */
@@ -49,20 +64,86 @@ export function rethrowError(prefix: string, error: unknown, recovered: VmAny |
49
64
 
50
65
  /** 标记参数为必须项 */
51
66
  export function required<const T = VmValue>(
52
- name: number | string,
67
+ name: ParamIndex,
53
68
  value: T | undefined,
54
69
  recovered: VmAny | (() => VmAny),
55
70
  ): asserts value is T {
56
71
  if (value === undefined) {
57
- if (typeof name == 'string') throwError(`Missing required parameter '${name}'`, recovered);
58
- const pos = name <= 0 ? 'first' : name <= 1 ? 'second' : name + 1 + 'th';
59
- throwError(`Missing required parameter at the ${pos} position`, recovered);
72
+ throwError(`${describeParam(name)} is required`, recovered);
60
73
  }
61
74
  }
62
75
 
76
+ /** 标记并转换参数为数字 */
77
+ export function expectNumber(name: ParamIndex, value: VmAny): number {
78
+ required(name, value, Number.NaN);
79
+ const v = toNumber(value, null);
80
+ if (v == null) {
81
+ throwUnconvertedTypeError(name, 'number', value, Number.NaN);
82
+ }
83
+ return v;
84
+ }
85
+ /** 标记并转换参数为数字 */
86
+ export function expectNumberRange(name: ParamIndex, value: VmAny, min: number, max: number): number {
87
+ const v = expectNumber(name, value);
88
+ if (!isFinite(v)) {
89
+ throwError(`${describeParam(name)} is not a finite number: ${display(value)}`, Number.NaN);
90
+ }
91
+ if (v < min) {
92
+ throwError(`${describeParam(name)} is less than minimum value ${min}: ${display(value)}`, min);
93
+ }
94
+ if (v > max) {
95
+ throwError(`${describeParam(name)} is greater than maximum value ${max}: ${display(value)}`, max);
96
+ }
97
+ return v;
98
+ }
99
+ /** 标记并转换参数为整数 */
100
+ export function expectIntegerRange(name: ParamIndex, value: VmAny, min: number, max: number): number {
101
+ const i = expectInteger(name, value);
102
+ if (i < min) {
103
+ throwError(`${describeParam(name)} is less than minimum value ${min}: ${display(value)}`, min);
104
+ }
105
+ if (i > max) {
106
+ throwError(`${describeParam(name)} is greater than maximum value ${max}: ${display(value)}`, max);
107
+ }
108
+ return i;
109
+ }
110
+ /** 标记并转换参数为整数 */
111
+ export function expectInteger(name: ParamIndex, value: VmAny): number {
112
+ required(name, value, 0);
113
+ const v = toNumber(value, null);
114
+ if (v == null) {
115
+ throwUnconvertedTypeError(name, 'integer', value, 0);
116
+ }
117
+ const i = Math.trunc(v);
118
+ if (!isSafeInteger(i)) {
119
+ throwUnconvertedTypeError(name, 'integer', value, 0);
120
+ }
121
+ return i;
122
+ }
123
+
124
+ /** 标记并转换参数为布尔值 */
125
+ export function expectBoolean(name: ParamIndex, value: VmAny): boolean {
126
+ required(name, value, false);
127
+ const v = toBoolean(value, null);
128
+ if (v == null) {
129
+ throwUnconvertedTypeError(name, 'boolean', value, false);
130
+ }
131
+ return v;
132
+ }
133
+
134
+ /** 标记并转换参数为字符串 */
135
+ export function expectString(name: ParamIndex, value: VmAny): string {
136
+ required(name, value, '');
137
+ const v = toString(value, null);
138
+ if (v == null) {
139
+ throwUnconvertedTypeError(name, 'string', value, '');
140
+ }
141
+ return v;
142
+ }
143
+
63
144
  /** 标记参数为数组 */
64
145
  export function expectArray(
65
- name: number | string,
146
+ name: ParamIndex,
66
147
  value: VmAny,
67
148
  recovered: VmAny | (() => VmAny),
68
149
  ): asserts value is VmArray {
@@ -74,7 +155,7 @@ export function expectArray(
74
155
 
75
156
  /** 标记参数为记录 */
76
157
  export function expectRecord(
77
- name: number | string,
158
+ name: ParamIndex,
78
159
  value: VmAny,
79
160
  recovered: VmAny | (() => VmAny),
80
161
  ): asserts value is VmRecord {
@@ -86,7 +167,7 @@ export function expectRecord(
86
167
 
87
168
  /** 标记参数为数组或记录 */
88
169
  export function expectArrayOrRecord(
89
- name: number | string,
170
+ name: ParamIndex,
90
171
  value: VmAny,
91
172
  recovered: VmAny | (() => VmAny),
92
173
  ): asserts value is VmArray | VmRecord {
@@ -98,7 +179,7 @@ export function expectArrayOrRecord(
98
179
 
99
180
  /** 标记参数为复合类型 */
100
181
  export function expectCompound(
101
- name: number | string,
182
+ name: ParamIndex,
102
183
  value: VmAny,
103
184
  recovered: VmAny | (() => VmAny),
104
185
  ): asserts value is VmArray | VmRecord | VmModule | VmExtern {
@@ -110,7 +191,7 @@ export function expectCompound(
110
191
 
111
192
  /** 标记参数为常量 */
112
193
  export function expectConst(
113
- name: number | string,
194
+ name: ParamIndex,
114
195
  value: VmAny,
115
196
  recovered: VmAny | (() => VmAny),
116
197
  ): asserts value is VmConst {
@@ -122,7 +203,7 @@ export function expectConst(
122
203
 
123
204
  /** 标记为可调用 */
124
205
  export function expectCallable(
125
- name: number | string,
206
+ name: ParamIndex,
126
207
  value: VmAny,
127
208
  recovered: VmAny | (() => VmAny),
128
209
  ): asserts value is VmFunction | VmExtern {
@@ -135,20 +216,27 @@ export function expectCallable(
135
216
  /** Get numbers from the arguments. */
136
217
  export function getNumbers(args: readonly VmAny[]): number[] {
137
218
  if (args.length === 0) return [];
138
- if (args.length === 1 && isVmArray(args[0])) args = args[0];
219
+ let useFirst = false;
220
+ if (args.length === 1 && isVmArray(args[0])) {
221
+ args = args[0];
222
+ useFirst = true;
223
+ }
139
224
  const numbers: number[] = [];
140
- for (const arg of args) {
141
- if (arg == null) continue;
142
- numbers.push($ToNumber(arg));
225
+ for (let len = args.length, i = 0; i < len; i++) {
226
+ numbers.push(expectNumber(useFirst ? null : i, args[i]));
143
227
  }
144
228
  return numbers;
145
229
  }
146
230
 
147
231
  /** 将值转为数组长度 */
148
232
  export function arrayLen(len: number | null | undefined): number {
149
- if (len == null || isNaN(len) || len <= 0) return 0;
233
+ if (len == null || isNaN(len) || len <= -1) {
234
+ throwError('Array length must be a non-negative integer', null);
235
+ }
150
236
  len = Math.trunc(len);
151
- if (len > VM_ARRAY_MAX_LENGTH) throwError(`Array length exceeds maximum limit of ${VM_ARRAY_MAX_LENGTH}`, null);
237
+ if (len > VM_ARRAY_MAX_LENGTH) {
238
+ throwError(`Array length exceeds maximum limit of ${VM_ARRAY_MAX_LENGTH}`, null);
239
+ }
152
240
  return len;
153
241
  }
154
242
 
@@ -191,7 +279,7 @@ export type VmLibOption = Pick<
191
279
  export type VmLib<T extends VmFunctionLike = VmFunctionLike> = T & VmLibOption;
192
280
 
193
281
  /** 创建库函数 */
194
- export function VmLib<T extends VmFunctionLike, P extends Record<string, unknown>>(
282
+ export function VmLib<const T extends VmFunctionLike, P extends Record<string, unknown> = Record<never, never>>(
195
283
  fn: T,
196
284
  option: VmLibOption,
197
285
  properties?: P,
@@ -200,7 +288,7 @@ export function VmLib<T extends VmFunctionLike, P extends Record<string, unknown
200
288
  if (typeof fn != 'function') throw new TypeError('Invalid function');
201
289
  if (isVmFunction(fn)) throw new TypeError('Cannot create VmLib from a VmFunction');
202
290
 
203
- const ret = fn as T & VmLibOption & P as Writable<T & VmLibOption & P>;
291
+ const ret = fn as Writable<VmLib<T>> & P;
204
292
  Object.assign(ret, properties);
205
293
  ret.params = option.params;
206
294
  ret.paramsType = option.paramsType;
@@ -208,5 +296,5 @@ export function VmLib<T extends VmFunctionLike, P extends Record<string, unknown
208
296
  ret.returnsType = option.returnsType;
209
297
  ret.summary = option.summary;
210
298
  ret.examples = option.examples;
211
- return ret as T & VmLibOption & P;
299
+ return ret as VmLib<T> & P;
212
300
  }
@@ -0,0 +1,16 @@
1
+ import * as global from './global/index.js';
2
+ import * as mods from './mod/index.js';
3
+ import { VM_SHARED_CONTEXT } from '../types/context.js';
4
+ import { create, entries } from '../../helpers/utils.js';
5
+ import { createModule, wrapEntry, type RawValue } from './loader.js';
6
+
7
+ for (const [name, value] of entries(global)) {
8
+ VM_SHARED_CONTEXT[name] = wrapEntry(name, value as RawValue, 'global');
9
+ }
10
+
11
+ for (const [name, value] of entries(mods)) {
12
+ const mod = createModule(name, value as Record<string, RawValue>);
13
+ VM_SHARED_CONTEXT[name] = wrapEntry(name, mod, 'global');
14
+ }
15
+
16
+ export const lib: Readonly<typeof global & typeof mods> = Object.freeze(Object.assign(create(null), global, mods));
@@ -1,20 +1,14 @@
1
1
  import { VmFunction, VmModule, type VmConst, type VmFunctionLike, type VmImmutable } from '../types/index.js';
2
2
  import { create, defineProperty, entries } from '../../helpers/utils.js';
3
- import { VmSharedContext } from '../types/context.js';
4
3
 
5
- import type { VmLib, VmLibOption } from './_helpers.js';
6
- import * as global from './global/index.js';
7
-
8
- for (const [name, value] of entries(global)) {
9
- VmSharedContext[name] = wrapEntry(name, value as RawValue, 'global');
10
- }
4
+ import type { VmLib, VmLibOption } from './helpers.js';
11
5
 
12
6
  /** 原始值 */
13
- type RawValue = VmLib | VmConst | VmModule;
7
+ export type RawValue = VmLib | VmConst | VmModule;
14
8
  /** 包装值 */
15
9
  type ToWrappedValue<V extends RawValue> = V extends VmFunctionLike ? VmFunction<V> : V;
16
10
  /** 包装值 */
17
- function wrapEntry<const T extends RawValue>(name: string, value: T, module: string): ToWrappedValue<T> {
11
+ export function wrapEntry<const T extends RawValue>(name: string, value: T, module: string): ToWrappedValue<T> {
18
12
  if (typeof value == 'function') {
19
13
  if (value.name !== name) {
20
14
  // 如果函数名和导出名不一致,则重命名
@@ -47,5 +41,3 @@ export function createModule<const T extends Record<string, RawValue>>(name: str
47
41
  }
48
42
  return new VmModule(name, mod) as ToWrappedModule<T>;
49
43
  }
50
-
51
- export const lib = global;
@@ -0,0 +1 @@
1
+ export * as matrix from './matrix.js';