ic-mops 1.11.1 → 2.0.0

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 (352) hide show
  1. package/.DS_Store +0 -0
  2. package/.eslintrc.json +7 -7
  3. package/CHANGELOG.md +15 -0
  4. package/api/actors.ts +41 -37
  5. package/api/downloadPackageFiles.ts +75 -61
  6. package/api/getHighestVersion.ts +5 -5
  7. package/api/index.ts +4 -4
  8. package/api/network.ts +19 -21
  9. package/api/resolveVersion.ts +14 -11
  10. package/bin/mops.js +1 -1
  11. package/bun.lock +234 -198
  12. package/bundle/bench/bench-canister.mo +2 -2
  13. package/bundle/bench/user-bench.mo +0 -4
  14. package/bundle/bin/mops.js +1 -1
  15. package/bundle/cli.js +1000 -924
  16. package/bundle/cli.tgz +0 -0
  17. package/bundle/declarations/bench/bench.did +3 -3
  18. package/bundle/declarations/bench/bench.did.d.ts +3 -3
  19. package/bundle/declarations/bench/index.d.ts +3 -3
  20. package/bundle/declarations/bench/index.js +1 -1
  21. package/bundle/declarations/main/index.d.ts +3 -3
  22. package/bundle/declarations/main/index.js +1 -1
  23. package/bundle/declarations/main/main.did +78 -121
  24. package/bundle/declarations/main/main.did.d.ts +48 -98
  25. package/bundle/declarations/main/main.did.js +53 -107
  26. package/bundle/declarations/storage/index.d.ts +3 -3
  27. package/bundle/declarations/storage/index.js +4 -4
  28. package/bundle/declarations/storage/storage.did.d.ts +3 -3
  29. package/bundle/package.json +6 -5
  30. package/bundle/templates/mops-publish.yml +3 -3
  31. package/bundle/templates/mops-test.yml +3 -3
  32. package/bundle-package-json.ts +8 -8
  33. package/cache.ts +80 -65
  34. package/check-requirements.ts +49 -45
  35. package/cli.ts +577 -376
  36. package/commands/add.ts +142 -129
  37. package/commands/available-updates.ts +55 -28
  38. package/commands/bench/bench-canister.mo +114 -108
  39. package/commands/bench/user-bench.mo +6 -6
  40. package/commands/bench-replica.ts +146 -106
  41. package/commands/bench.ts +563 -497
  42. package/commands/build.ts +177 -0
  43. package/commands/bump.ts +68 -57
  44. package/commands/check-candid.ts +24 -0
  45. package/commands/docs-coverage.ts +124 -102
  46. package/commands/docs.ts +118 -108
  47. package/commands/format.ts +171 -155
  48. package/commands/init.ts +301 -275
  49. package/commands/install/install-all.ts +75 -62
  50. package/commands/install/install-dep.ts +43 -28
  51. package/commands/install/install-deps.ts +23 -15
  52. package/commands/install/install-local-dep.ts +42 -34
  53. package/commands/install/install-mops-dep.ts +154 -123
  54. package/commands/install/sync-local-cache.ts +39 -35
  55. package/commands/maintainer.ts +109 -99
  56. package/commands/outdated.ts +31 -18
  57. package/commands/owner.ts +107 -99
  58. package/commands/publish.ts +534 -443
  59. package/commands/remove.ts +119 -89
  60. package/commands/replica.ts +391 -303
  61. package/commands/search.ts +42 -36
  62. package/commands/self.ts +63 -56
  63. package/commands/sources.ts +66 -49
  64. package/commands/sync.ts +92 -75
  65. package/commands/template.ts +145 -102
  66. package/commands/test/mmf1.ts +146 -119
  67. package/commands/test/reporters/compact-reporter.ts +87 -84
  68. package/commands/test/reporters/files-reporter.ts +56 -51
  69. package/commands/test/reporters/reporter.ts +12 -6
  70. package/commands/test/reporters/silent-reporter.ts +58 -59
  71. package/commands/test/reporters/verbose-reporter.ts +66 -54
  72. package/commands/test/test.ts +497 -460
  73. package/commands/test/utils.ts +85 -6
  74. package/commands/toolchain/index.ts +363 -322
  75. package/commands/toolchain/moc.ts +78 -50
  76. package/commands/toolchain/pocket-ic.ts +41 -34
  77. package/commands/toolchain/toolchain-utils.ts +92 -72
  78. package/commands/toolchain/wasmtime.ts +37 -34
  79. package/commands/update.ts +91 -56
  80. package/commands/user.ts +90 -81
  81. package/commands/watch/deployer.ts +188 -152
  82. package/commands/watch/error-checker.ts +90 -80
  83. package/commands/watch/formatter.ts +72 -60
  84. package/commands/watch/generator.ts +116 -96
  85. package/commands/watch/globMoFiles.ts +13 -13
  86. package/commands/watch/parseDfxJson.ts +63 -57
  87. package/commands/watch/tester.ts +83 -65
  88. package/commands/watch/warning-checker.ts +149 -136
  89. package/commands/watch/watch.ts +123 -95
  90. package/declarations/bench/bench.did.d.ts +3 -3
  91. package/declarations/bench/index.d.ts +3 -3
  92. package/declarations/bench/index.js +1 -1
  93. package/declarations/main/index.d.ts +3 -3
  94. package/declarations/main/index.js +1 -1
  95. package/declarations/main/main.did.d.ts +3 -3
  96. package/declarations/storage/index.d.ts +3 -3
  97. package/declarations/storage/index.js +4 -4
  98. package/declarations/storage/storage.did.d.ts +3 -3
  99. package/dist/api/actors.d.ts +4 -4
  100. package/dist/api/actors.js +8 -8
  101. package/dist/api/downloadPackageFiles.d.ts +2 -2
  102. package/dist/api/downloadPackageFiles.js +10 -10
  103. package/dist/api/getHighestVersion.js +1 -1
  104. package/dist/api/index.d.ts +4 -4
  105. package/dist/api/index.js +4 -4
  106. package/dist/api/network.js +9 -9
  107. package/dist/api/resolveVersion.js +3 -3
  108. package/dist/bin/mops.js +1 -1
  109. package/dist/bundle-package-json.js +8 -8
  110. package/dist/cache.js +22 -17
  111. package/dist/check-requirements.js +11 -11
  112. package/dist/cli.js +283 -186
  113. package/dist/commands/add.d.ts +1 -1
  114. package/dist/commands/add.js +41 -38
  115. package/dist/commands/available-updates.d.ts +1 -1
  116. package/dist/commands/available-updates.js +32 -14
  117. package/dist/commands/bench/bench-canister.mo +114 -108
  118. package/dist/commands/bench/user-bench.mo +6 -6
  119. package/dist/commands/bench-replica.d.ts +6 -5
  120. package/dist/commands/bench-replica.js +58 -36
  121. package/dist/commands/bench.d.ts +5 -5
  122. package/dist/commands/bench.js +134 -118
  123. package/dist/commands/build.d.ts +7 -0
  124. package/dist/commands/build.js +121 -0
  125. package/dist/commands/bump.js +27 -18
  126. package/dist/commands/check-candid.d.ts +4 -0
  127. package/dist/commands/check-candid.js +15 -0
  128. package/dist/commands/docs-coverage.d.ts +1 -1
  129. package/dist/commands/docs-coverage.js +45 -31
  130. package/dist/commands/docs.d.ts +1 -1
  131. package/dist/commands/docs.js +39 -38
  132. package/dist/commands/format.js +31 -27
  133. package/dist/commands/init.js +102 -92
  134. package/dist/commands/install/install-all.d.ts +2 -2
  135. package/dist/commands/install/install-all.js +23 -21
  136. package/dist/commands/install/install-dep.d.ts +1 -1
  137. package/dist/commands/install/install-dep.js +21 -8
  138. package/dist/commands/install/install-deps.d.ts +1 -1
  139. package/dist/commands/install/install-deps.js +1 -1
  140. package/dist/commands/install/install-local-dep.js +11 -9
  141. package/dist/commands/install/install-mops-dep.d.ts +1 -1
  142. package/dist/commands/install/install-mops-dep.js +32 -27
  143. package/dist/commands/install/sync-local-cache.js +10 -10
  144. package/dist/commands/maintainer.js +21 -21
  145. package/dist/commands/outdated.js +16 -6
  146. package/dist/commands/owner.js +21 -21
  147. package/dist/commands/publish.js +148 -128
  148. package/dist/commands/remove.d.ts +1 -1
  149. package/dist/commands/remove.js +42 -30
  150. package/dist/commands/replica.d.ts +9 -8
  151. package/dist/commands/replica.js +105 -65
  152. package/dist/commands/search.js +15 -13
  153. package/dist/commands/self.js +31 -28
  154. package/dist/commands/sources.d.ts +5 -1
  155. package/dist/commands/sources.js +23 -17
  156. package/dist/commands/sync.d.ts +1 -1
  157. package/dist/commands/sync.js +38 -25
  158. package/dist/commands/template.js +66 -56
  159. package/dist/commands/test/mmf1.d.ts +3 -3
  160. package/dist/commands/test/mmf1.js +33 -31
  161. package/dist/commands/test/reporters/compact-reporter.d.ts +3 -3
  162. package/dist/commands/test/reporters/compact-reporter.js +19 -15
  163. package/dist/commands/test/reporters/files-reporter.d.ts +3 -3
  164. package/dist/commands/test/reporters/files-reporter.js +18 -14
  165. package/dist/commands/test/reporters/reporter.d.ts +2 -2
  166. package/dist/commands/test/reporters/silent-reporter.d.ts +3 -3
  167. package/dist/commands/test/reporters/silent-reporter.js +4 -4
  168. package/dist/commands/test/reporters/verbose-reporter.d.ts +3 -3
  169. package/dist/commands/test/reporters/verbose-reporter.js +17 -13
  170. package/dist/commands/test/test.d.ts +4 -4
  171. package/dist/commands/test/test.js +151 -181
  172. package/dist/commands/test/utils.d.ts +6 -0
  173. package/dist/commands/test/utils.js +63 -2
  174. package/dist/commands/toolchain/index.d.ts +1 -1
  175. package/dist/commands/toolchain/index.js +81 -69
  176. package/dist/commands/toolchain/moc.d.ts +1 -1
  177. package/dist/commands/toolchain/moc.js +48 -24
  178. package/dist/commands/toolchain/pocket-ic.js +12 -12
  179. package/dist/commands/toolchain/toolchain-utils.d.ts +2 -0
  180. package/dist/commands/toolchain/toolchain-utils.js +32 -23
  181. package/dist/commands/toolchain/wasmtime.js +11 -11
  182. package/dist/commands/update.d.ts +1 -1
  183. package/dist/commands/update.js +30 -12
  184. package/dist/commands/user.js +31 -28
  185. package/dist/commands/watch/deployer.d.ts +4 -4
  186. package/dist/commands/watch/deployer.js +45 -36
  187. package/dist/commands/watch/error-checker.d.ts +2 -2
  188. package/dist/commands/watch/error-checker.js +27 -27
  189. package/dist/commands/watch/formatter.d.ts +4 -4
  190. package/dist/commands/watch/formatter.js +17 -17
  191. package/dist/commands/watch/generator.d.ts +3 -3
  192. package/dist/commands/watch/generator.js +28 -23
  193. package/dist/commands/watch/globMoFiles.js +8 -8
  194. package/dist/commands/watch/parseDfxJson.d.ts +2 -2
  195. package/dist/commands/watch/parseDfxJson.js +9 -9
  196. package/dist/commands/watch/tester.d.ts +4 -4
  197. package/dist/commands/watch/tester.js +23 -21
  198. package/dist/commands/watch/warning-checker.d.ts +3 -3
  199. package/dist/commands/watch/warning-checker.js +36 -36
  200. package/dist/commands/watch/watch.js +45 -32
  201. package/dist/declarations/bench/bench.did.d.ts +3 -3
  202. package/dist/declarations/bench/index.d.ts +3 -3
  203. package/dist/declarations/bench/index.js +1 -1
  204. package/dist/declarations/main/index.d.ts +3 -3
  205. package/dist/declarations/main/index.js +1 -1
  206. package/dist/declarations/main/main.did.d.ts +3 -3
  207. package/dist/declarations/storage/index.d.ts +3 -3
  208. package/dist/declarations/storage/index.js +4 -4
  209. package/dist/declarations/storage/storage.did.d.ts +3 -3
  210. package/dist/environments/nodejs/cli.d.ts +1 -0
  211. package/dist/environments/nodejs/cli.js +4 -0
  212. package/dist/environments/web/cli.d.ts +1 -0
  213. package/dist/environments/web/cli.js +4 -0
  214. package/dist/error.d.ts +1 -0
  215. package/dist/error.js +5 -0
  216. package/dist/fix-dist.js +5 -5
  217. package/dist/helpers/find-changelog-entry.js +8 -5
  218. package/dist/helpers/get-dep-name.d.ts +1 -0
  219. package/dist/helpers/get-dep-name.js +4 -1
  220. package/dist/helpers/get-dfx-version.js +4 -4
  221. package/dist/helpers/get-moc-path.js +8 -7
  222. package/dist/helpers/get-moc-version.js +10 -7
  223. package/dist/helpers/get-package-id.js +2 -2
  224. package/dist/helpers/is-candid-compatible.d.ts +1 -0
  225. package/dist/helpers/is-candid-compatible.js +20 -0
  226. package/dist/integrity.d.ts +1 -1
  227. package/dist/integrity.js +47 -38
  228. package/dist/jest.config.d.ts +11 -0
  229. package/dist/jest.config.js +14 -0
  230. package/dist/mops.d.ts +6 -6
  231. package/dist/mops.js +87 -80
  232. package/dist/notify-installs.js +4 -4
  233. package/dist/package.json +11 -10
  234. package/dist/pem.d.ts +3 -3
  235. package/dist/pem.js +20 -12
  236. package/dist/release-cli.js +20 -20
  237. package/dist/resolve-packages.d.ts +1 -1
  238. package/dist/resolve-packages.js +52 -36
  239. package/dist/templates/mops-publish.yml +3 -3
  240. package/dist/templates/mops-test.yml +3 -3
  241. package/dist/templates/src/lib.mo +13 -13
  242. package/dist/templates/test/lib.test.mo +2 -2
  243. package/dist/templates.js +1 -1
  244. package/dist/tests/cli.test.d.ts +1 -0
  245. package/dist/tests/cli.test.js +63 -0
  246. package/dist/types.d.ts +14 -4
  247. package/dist/vessel.d.ts +2 -2
  248. package/dist/vessel.js +41 -34
  249. package/dist/wasm/pkg/bundler/package.json +20 -0
  250. package/dist/wasm/pkg/bundler/wasm.d.ts +3 -0
  251. package/dist/wasm/pkg/bundler/wasm.js +5 -0
  252. package/dist/wasm/pkg/bundler/wasm_bg.js +93 -0
  253. package/dist/wasm/pkg/bundler/wasm_bg.wasm +0 -0
  254. package/dist/wasm/pkg/bundler/wasm_bg.wasm.d.ts +8 -0
  255. package/dist/wasm/pkg/nodejs/package.json +14 -0
  256. package/dist/wasm/pkg/nodejs/wasm.d.ts +3 -0
  257. package/dist/wasm/pkg/nodejs/wasm.js +98 -0
  258. package/dist/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
  259. package/dist/wasm/pkg/nodejs/wasm_bg.wasm.d.ts +8 -0
  260. package/dist/wasm/pkg/web/package.json +18 -0
  261. package/dist/wasm/pkg/web/wasm.d.ts +35 -0
  262. package/dist/wasm/pkg/web/wasm.js +191 -0
  263. package/dist/wasm/pkg/web/wasm_bg.wasm +0 -0
  264. package/dist/wasm/pkg/web/wasm_bg.wasm.d.ts +8 -0
  265. package/dist/wasm.d.ts +5 -0
  266. package/dist/wasm.js +10 -0
  267. package/environments/nodejs/cli.ts +6 -0
  268. package/environments/web/cli.ts +6 -0
  269. package/error.ts +6 -0
  270. package/fix-dist.ts +5 -5
  271. package/global.d.ts +3 -3
  272. package/helpers/find-changelog-entry.ts +26 -23
  273. package/helpers/get-dep-name.ts +7 -3
  274. package/helpers/get-dfx-version.ts +8 -9
  275. package/helpers/get-moc-path.ts +25 -26
  276. package/helpers/get-moc-version.ts +21 -19
  277. package/helpers/get-package-id.ts +4 -4
  278. package/helpers/is-candid-compatible.ts +22 -0
  279. package/integrity.ts +270 -236
  280. package/jest.config.js +14 -0
  281. package/mops.ts +238 -215
  282. package/notify-installs.ts +16 -17
  283. package/package.json +21 -15
  284. package/parallel.ts +28 -24
  285. package/pem.ts +55 -47
  286. package/release-cli.ts +73 -39
  287. package/resolve-packages.ts +231 -189
  288. package/templates/mops-publish.yml +3 -3
  289. package/templates/mops-test.yml +3 -3
  290. package/templates/src/lib.mo +13 -13
  291. package/templates/test/lib.test.mo +2 -2
  292. package/templates.ts +4 -4
  293. package/tests/__snapshots__/cli.test.ts.snap +202 -0
  294. package/tests/build/error/candid/bar.did +3 -0
  295. package/tests/build/error/dfx.json +12 -0
  296. package/tests/build/error/mops.toml +9 -0
  297. package/tests/build/error/src/Bar.mo +5 -0
  298. package/tests/build/error/src/Foo.mo +5 -0
  299. package/tests/build/success/.dfx/local/canister_ids.json +17 -0
  300. package/tests/build/success/.dfx/local/canisters/bar/bar.did +3 -0
  301. package/tests/build/success/.dfx/local/canisters/bar/bar.most +4 -0
  302. package/tests/build/success/.dfx/local/canisters/bar/bar.wasm +0 -0
  303. package/tests/build/success/.dfx/local/canisters/bar/constructor.did +3 -0
  304. package/tests/build/success/.dfx/local/canisters/bar/index.js +42 -0
  305. package/tests/build/success/.dfx/local/canisters/bar/init_args.txt +1 -0
  306. package/tests/build/success/.dfx/local/canisters/bar/service.did +3 -0
  307. package/tests/build/success/.dfx/local/canisters/bar/service.did.d.ts +7 -0
  308. package/tests/build/success/.dfx/local/canisters/bar/service.did.js +4 -0
  309. package/tests/build/success/.dfx/local/canisters/foo/constructor.did +3 -0
  310. package/tests/build/success/.dfx/local/canisters/foo/foo.did +3 -0
  311. package/tests/build/success/.dfx/local/canisters/foo/foo.most +4 -0
  312. package/tests/build/success/.dfx/local/canisters/foo/foo.wasm +0 -0
  313. package/tests/build/success/.dfx/local/canisters/foo/index.js +42 -0
  314. package/tests/build/success/.dfx/local/canisters/foo/init_args.txt +1 -0
  315. package/tests/build/success/.dfx/local/canisters/foo/service.did +3 -0
  316. package/tests/build/success/.dfx/local/canisters/foo/service.did.d.ts +7 -0
  317. package/tests/build/success/.dfx/local/canisters/foo/service.did.js +4 -0
  318. package/tests/build/success/.dfx/local/lsp/ucwa4-rx777-77774-qaada-cai.did +3 -0
  319. package/tests/build/success/.dfx/local/lsp/ulvla-h7777-77774-qaacq-cai.did +3 -0
  320. package/tests/build/success/.dfx/local/network-id +4 -0
  321. package/tests/build/success/candid/bar.did +3 -0
  322. package/tests/build/success/dfx.json +12 -0
  323. package/tests/build/success/mops.toml +9 -0
  324. package/tests/build/success/src/Bar.mo +5 -0
  325. package/tests/build/success/src/Foo.mo +5 -0
  326. package/tests/check-candid/a.did +3 -0
  327. package/tests/check-candid/b.did +5 -0
  328. package/tests/check-candid/c.did +3 -0
  329. package/tests/cli.test.ts +82 -0
  330. package/tsconfig.json +26 -19
  331. package/types.ts +41 -31
  332. package/vessel.ts +219 -187
  333. package/wasm/Cargo.lock +1475 -0
  334. package/wasm/Cargo.toml +28 -0
  335. package/wasm/pkg/bundler/package.json +20 -0
  336. package/wasm/pkg/bundler/wasm.d.ts +3 -0
  337. package/wasm/pkg/bundler/wasm.js +5 -0
  338. package/wasm/pkg/bundler/wasm_bg.js +93 -0
  339. package/wasm/pkg/bundler/wasm_bg.wasm +0 -0
  340. package/wasm/pkg/bundler/wasm_bg.wasm.d.ts +8 -0
  341. package/wasm/pkg/nodejs/package.json +14 -0
  342. package/wasm/pkg/nodejs/wasm.d.ts +3 -0
  343. package/wasm/pkg/nodejs/wasm.js +98 -0
  344. package/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
  345. package/wasm/pkg/nodejs/wasm_bg.wasm.d.ts +8 -0
  346. package/wasm/pkg/web/package.json +18 -0
  347. package/wasm/pkg/web/wasm.d.ts +35 -0
  348. package/wasm/pkg/web/wasm.js +191 -0
  349. package/wasm/pkg/web/wasm_bg.wasm +0 -0
  350. package/wasm/pkg/web/wasm_bg.wasm.d.ts +8 -0
  351. package/wasm/src/lib.rs +17 -0
  352. package/wasm.ts +16 -0
@@ -1,479 +1,516 @@
1
- import process from 'node:process';
2
- import {spawn, ChildProcessWithoutNullStreams} from 'node:child_process';
3
- import path from 'node:path';
4
- import fs from 'node:fs';
5
- import os from 'node:os';
6
-
7
- import chalk from 'chalk';
8
- import {globSync} from 'glob';
9
- import chokidar from 'chokidar';
10
- import debounce from 'debounce';
11
- import {SemVer} from 'semver';
12
-
13
- import {sources} from '../sources.js';
14
- import {getRootDir, readConfig} from '../../mops.js';
15
- import {parallel} from '../../parallel.js';
16
-
17
- import {MMF1} from './mmf1.js';
18
- import {absToRel} from './utils.js';
19
- import {Reporter} from './reporters/reporter.js';
20
- import {VerboseReporter} from './reporters/verbose-reporter.js';
21
- import {FilesReporter} from './reporters/files-reporter.js';
22
- import {CompactReporter} from './reporters/compact-reporter.js';
23
- import {SilentReporter} from './reporters/silent-reporter.js';
24
- import {toolchain} from '../toolchain/index.js';
25
- import {Replica} from '../replica.js';
26
- import {ActorMethod} from '@dfinity/agent';
27
- import {PassThrough, Readable} from 'node:stream';
28
- import {TestMode} from '../../types.js';
29
- import {getDfxVersion} from '../../helpers/get-dfx-version.js';
1
+ import process from "node:process";
2
+ import { spawn } from "node:child_process";
3
+ import path from "node:path";
4
+ import fs from "node:fs";
5
+ import os from "node:os";
6
+ import { PassThrough } from "node:stream";
7
+
8
+ import chalk from "chalk";
9
+ import { globSync } from "glob";
10
+ import chokidar from "chokidar";
11
+ import debounce from "debounce";
12
+ import { SemVer } from "semver";
13
+ import { ActorMethod } from "@icp-sdk/core/agent";
14
+
15
+ import { sources } from "../sources.js";
16
+ import { getRootDir, readConfig } from "../../mops.js";
17
+ import { parallel } from "../../parallel.js";
18
+
19
+ import { MMF1 } from "./mmf1.js";
20
+ import {
21
+ absToRel,
22
+ pipeMMF,
23
+ pipeStderrToMMF,
24
+ pipeStdoutToMMF,
25
+ } from "./utils.js";
26
+ import { Reporter } from "./reporters/reporter.js";
27
+ import { VerboseReporter } from "./reporters/verbose-reporter.js";
28
+ import { FilesReporter } from "./reporters/files-reporter.js";
29
+ import { CompactReporter } from "./reporters/compact-reporter.js";
30
+ import { SilentReporter } from "./reporters/silent-reporter.js";
31
+ import { toolchain } from "../toolchain/index.js";
32
+ import { Replica } from "../replica.js";
33
+ import { TestMode } from "../../types.js";
34
+ import { getDfxVersion } from "../../helpers/get-dfx-version.js";
30
35
 
31
36
  let ignore = [
32
- '**/node_modules/**',
33
- '**/.mops/**',
34
- '**/.vessel/**',
35
- '**/.git/**',
37
+ "**/node_modules/**",
38
+ "**/.mops/**",
39
+ "**/.vessel/**",
40
+ "**/.git/**",
36
41
  ];
37
42
 
38
43
  let globConfig = {
39
- nocase: true,
40
- ignore: ignore,
44
+ nocase: true,
45
+ ignore: ignore,
41
46
  };
42
47
 
43
- type ReporterName = 'verbose' | 'files' | 'compact' | 'silent';
44
- type ReplicaName = 'dfx' | 'pocket-ic' | 'dfx-pocket-ic';
48
+ type ReporterName = "verbose" | "files" | "compact" | "silent";
49
+ type ReplicaName = "dfx" | "pocket-ic" | "dfx-pocket-ic";
45
50
 
46
51
  type TestOptions = {
47
- watch : boolean;
48
- reporter : ReporterName;
49
- mode : TestMode;
50
- replica : ReplicaName;
51
- verbose : boolean;
52
+ watch: boolean;
53
+ reporter: ReporterName;
54
+ mode: TestMode;
55
+ replica: ReplicaName;
56
+ verbose: boolean;
52
57
  };
53
58
 
54
-
55
59
  let replica = new Replica();
56
- let replicaStartPromise : Promise<void> | undefined;
57
-
58
- async function startReplicaOnce(replica : Replica, type : ReplicaName) {
59
- if (!replicaStartPromise) {
60
- replicaStartPromise = new Promise((resolve) => {
61
- replica.start({type, silent: true}).then(resolve);
62
- });
63
- }
64
- return replicaStartPromise;
65
- }
66
-
67
- export async function test(filter = '', options : Partial<TestOptions> = {}) {
68
- let config = readConfig();
69
- let rootDir = getRootDir();
70
-
71
- let replicaType = options.replica ?? (config.toolchain?.['pocket-ic'] ? 'pocket-ic' : 'dfx' as ReplicaName);
72
-
73
- if (replicaType === 'pocket-ic' && !config.toolchain?.['pocket-ic']) {
74
- let dfxVersion = getDfxVersion();
75
- if (!dfxVersion || new SemVer(dfxVersion).compare('0.24.1') < 0) {
76
- console.log(chalk.red('Please update dfx to the version >=0.24.1 or specify pocket-ic version in mops.toml'));
77
- process.exit(1);
78
- }
79
- else {
80
- replicaType = 'dfx-pocket-ic';
81
- }
82
- }
83
-
84
- replica.type = replicaType;
85
- replica.verbose = !!options.verbose;
86
-
87
- if (options.watch) {
88
- replica.ttl = 60 * 15; // 15 minutes
89
-
90
- let sigint = false;
91
- process.on('SIGINT', () => {
92
- if (sigint) {
93
- console.log('Force exit');
94
- process.exit(0);
95
- }
96
- sigint = true;
97
-
98
- if (replicaStartPromise) {
99
- console.log('Stopping replica...');
100
- replica.stop(true).then(() => {
101
- process.exit(0);
102
- });
103
- }
104
- else {
105
- process.exit(0);
106
- }
107
- });
108
-
109
- // todo: run only changed for *.test.mo?
110
- // todo: run all for *.mo?
111
-
112
- let curRun = Promise.resolve(true);
113
- let controller = new AbortController();
114
-
115
- let run = debounce(async () => {
116
- controller.abort();
117
- await curRun;
118
-
119
- console.clear();
120
- process.stdout.write('\x1Bc');
121
-
122
- controller = new AbortController();
123
- curRun = runAll(options.reporter, filter, options.mode, replicaType, true, controller.signal);
124
- await curRun;
125
-
126
- console.log('-'.repeat(50));
127
- console.log('Waiting for file changes...');
128
- console.log(chalk.gray((`Press ${chalk.gray('Ctrl+C')} to exit.`)));
129
- }, 200);
130
-
131
- let watcher = chokidar.watch([
132
- path.join(rootDir, '**/*.mo'),
133
- path.join(rootDir, 'mops.toml'),
134
- ], {
135
- ignored: ignore,
136
- ignoreInitial: true,
137
- });
138
-
139
- watcher.on('all', () => {
140
- run();
141
- });
142
- run();
143
- }
144
- else {
145
- let passed = await runAll(options.reporter, filter, options.mode, replicaType);
146
- if (!passed) {
147
- process.exit(1);
148
- }
149
- }
150
- }
151
-
152
- let mocPath = '';
153
- let wasmtimePath = '';
154
-
155
- async function runAll(reporterName : ReporterName | undefined, filter = '', mode : TestMode = 'interpreter', replicaType : ReplicaName, watch = false, signal ?: AbortSignal) : Promise<boolean> {
156
- let done = await testWithReporter(reporterName, filter, mode, replicaType, watch, signal);
157
- return done;
158
- }
159
-
160
- export async function testWithReporter(reporterName : ReporterName | Reporter | undefined, filter = '', defaultMode : TestMode = 'interpreter', replicaType : ReplicaName, watch = false, signal ?: AbortSignal) : Promise<boolean> {
161
- let rootDir = getRootDir();
162
- let files : string[] = [];
163
- let libFiles = globSync('**/test?(s)/lib.mo', globConfig);
164
- if (libFiles[0]) {
165
- files = [libFiles[0]];
166
- }
167
- else {
168
- let globStr = '**/test?(s)/**/*.test.mo';
169
- if (filter) {
170
- globStr = `**/test?(s)/**/*${filter}*.mo`;
171
- }
172
- files = globSync(path.join(rootDir, globStr), globConfig);
173
- }
174
- if (!files.length) {
175
- if (filter) {
176
- console.log(`No test files found for filter '${filter}'`);
177
- return false;
178
- }
179
- console.log('No test files found');
180
- console.log('Put your tests in \'test\' directory in *.test.mo files');
181
- return false;
182
- }
183
-
184
-
185
- let reporter : Reporter;
186
-
187
- if (!reporterName || typeof reporterName === 'string') {
188
- if (!reporterName) {
189
- reporterName = files.length > 1 ? 'files' : 'verbose';
190
- }
191
-
192
- if (reporterName == 'compact') {
193
- reporter = new CompactReporter;
194
- }
195
- else if (reporterName == 'files') {
196
- reporter = new FilesReporter;
197
- }
198
- else if (reporterName == 'silent') {
199
- reporter = new SilentReporter;
200
- }
201
- else {
202
- reporter = new VerboseReporter;
203
- }
204
- }
205
- else {
206
- reporter = reporterName;
207
- }
208
-
209
- reporter.addFiles(files);
210
-
211
- let config = readConfig();
212
- let sourcesArr = await sources();
213
-
214
- if (!mocPath) {
215
- mocPath = await toolchain.bin('moc', {fallback: true});
216
- }
217
-
218
- let testTempDir = path.join(getRootDir(), '.mops/.test/');
219
- replica.dir = testTempDir;
220
-
221
- fs.rmSync(testTempDir, {recursive: true, force: true});
222
- fs.mkdirSync(testTempDir, {recursive: true});
223
-
224
- await parallel(os.cpus().length, files, async (file : string) => {
225
- if (signal?.aborted) {
226
- return;
227
- }
228
-
229
- let mmf = new MMF1('store', absToRel(file));
230
-
231
- // mode overrides
232
- let lines = fs.readFileSync(file, 'utf8').split('\n');
233
- let mode = defaultMode;
234
- if (lines.includes('// @testmode wasi')) {
235
- mode = 'wasi';
236
- }
237
- else if (lines.includes('// @testmode replica') || lines.find(line => line.match(/^(persistent )?actor( class)?/))) {
238
- mode = 'replica';
239
- }
240
-
241
- if (mode === 'wasi' && !wasmtimePath) {
242
- // ensure wasmtime is installed or specified in config
243
- if (config.toolchain?.wasmtime) {
244
- wasmtimePath = await toolchain.bin('wasmtime');
245
- }
246
- // fallback wasmtime to global binary if not specified in config (legacy)
247
- else {
248
- wasmtimePath = 'wasmtime';
249
- console.log(chalk.yellow('Warning:'), 'Wasmtime is not specified in config. Using global binary "wasmtime". This will be removed in the future.');
250
- console.log(`Run ${chalk.green('mops toolchain use wasmtime')} or add ${chalk.green('wasmtime = "<version>"')} in mops.toml to avoid breaking changes with future versions of mops.`);
251
- }
252
- }
253
-
254
- let promise = new Promise<void>((resolve) => {
255
- let mocArgs = ['--hide-warnings', '--error-detail=2', ...sourcesArr.join(' ').split(' '), file].filter(x => x);
256
-
257
- // interpret
258
- if (mode === 'interpreter') {
259
- let proc = spawn(mocPath, ['-r', '-ref-system-api', ...mocArgs], {signal});
260
- proc.addListener('error', (error : any) => {
261
- if (error?.code === 'ABORT_ERR') {
262
- return;
263
- }
264
- throw error;
265
- });
266
- pipeMMF(proc, mmf).then(resolve);
267
- }
268
- // build and run wasm
269
- else if (mode === 'wasi') {
270
- let wasmFile = `${path.join(testTempDir, path.parse(file).name)}.wasm`;
271
-
272
- // build
273
- let buildProc = spawn(mocPath, [`-o=${wasmFile}`, '-wasi-system-api', ...mocArgs], {signal});
274
- buildProc.addListener('error', (error : any) => {
275
- if (error?.code === 'ABORT_ERR') {
276
- return;
277
- }
278
- throw error;
279
- });
280
- pipeMMF(buildProc, mmf).then(async () => {
281
- if (mmf.failed > 0) {
282
- return;
283
- }
284
- // run
285
- let wasmtimeArgs = [];
286
- if (config.toolchain?.wasmtime && config.toolchain?.wasmtime >= '14.0.0') {
287
- wasmtimeArgs = [
288
- '-S', 'preview2=n',
289
- '-C', 'cache=n',
290
- '-W', 'bulk-memory',
291
- '-W', 'multi-memory',
292
- '-W', 'memory64',
293
- '-W', 'max-wasm-stack=4000000',
294
- '-W', 'nan-canonicalization=y',
295
- wasmFile,
296
- ];
297
- }
298
- else {
299
- console.error(chalk.red('Minimum wasmtime version is 14.0.0. Please update wasmtime to the latest version'));
300
- process.exit(1);
301
- }
302
-
303
- let proc = spawn(wasmtimePath, wasmtimeArgs, {signal});
304
- proc.addListener('error', (error : any) => {
305
- if (error?.code === 'ABORT_ERR') {
306
- return;
307
- }
308
- throw error;
309
- });
310
-
311
- await pipeMMF(proc, mmf);
312
- }).finally(() => {
313
- fs.rmSync(wasmFile, {force: true});
314
- }).then(resolve);
315
- }
316
- // build and execute in replica
317
- else if (mode === 'replica') {
318
- // mmf.strategy = 'print'; // because we run replica tests one-by-one
319
-
320
- let wasmFile = `${path.join(testTempDir, path.parse(file).name)}.wasm`;
321
-
322
- // build
323
- let buildProc = spawn(mocPath, [`-o=${wasmFile}`, ...mocArgs], {signal});
324
- buildProc.addListener('error', (error : any) => {
325
- if (error?.code === 'ABORT_ERR') {
326
- return;
327
- }
328
- throw error;
329
- });
330
-
331
- pipeMMF(buildProc, mmf).then(async () => {
332
- if (mmf.failed > 0) {
333
- return;
334
- }
335
-
336
- await startReplicaOnce(replica, replicaType);
337
-
338
- if (signal?.aborted) {
339
- return;
340
- }
341
-
342
- let canisterName = path.parse(file).name;
343
- let idlFactory = ({IDL} : any) => {
344
- return IDL.Service({'runTests': IDL.Func([], [], [])});
345
- };
346
- interface _SERVICE {'runTests' : ActorMethod<[], undefined>;}
347
-
348
- let canister = await replica.deploy(canisterName, wasmFile, idlFactory, undefined, signal);
349
-
350
- if (signal?.aborted || !canister) {
351
- return;
352
- }
353
-
354
- pipeStdoutToMMF(canister.stream, mmf);
355
-
356
- let actor = await replica.getActor(canisterName) as _SERVICE;
357
-
358
- try {
359
- if (globalThis.mopsReplicaTestRunning) {
360
- await new Promise<void>((resolve) => {
361
- let timerId = setInterval(() => {
362
- if (!globalThis.mopsReplicaTestRunning) {
363
- resolve();
364
- clearInterval(timerId);
365
- }
366
- }, Math.random() * 1000 |0);
367
- });
368
- }
369
-
370
- if (signal?.aborted) {
371
- return;
372
- }
373
-
374
- globalThis.mopsReplicaTestRunning = true;
375
- await actor.runTests();
376
- globalThis.mopsReplicaTestRunning = false;
377
-
378
- mmf.pass();
379
- }
380
- catch (e : any) {
381
- let stderrStream = new PassThrough();
382
- pipeStderrToMMF(stderrStream, mmf, path.dirname(file));
383
- stderrStream.write(e.message);
384
- }
385
- }).finally(async () => {
386
- globalThis.mopsReplicaTestRunning = false;
387
- fs.rmSync(wasmFile, {force: true});
388
- }).then(resolve);
389
- }
390
- });
391
-
392
- if (signal?.aborted) {
393
- return;
394
- }
395
-
396
- reporter.addRun(file, mmf, promise, mode);
397
-
398
- await promise;
399
- });
400
-
401
- if (replicaStartPromise && !watch) {
402
- await replica.stop();
403
- fs.rmSync(testTempDir, {recursive: true, force: true});
404
- }
405
-
406
- if (signal?.aborted) {
407
- return false;
408
- }
409
-
410
- return reporter.done();
60
+ let replicaStartPromise: Promise<void> | undefined;
61
+
62
+ async function startReplicaOnce(replica: Replica, type: ReplicaName) {
63
+ if (!replicaStartPromise) {
64
+ replicaStartPromise = new Promise((resolve) => {
65
+ replica.start({ type, silent: true }).then(resolve);
66
+ });
67
+ }
68
+ return replicaStartPromise;
411
69
  }
412
70
 
413
- function pipeStdoutToMMF(stdout : Readable, mmf : MMF1) {
414
- stdout.on('data', (data) => {
415
- for (let line of data.toString().split('\n')) {
416
- line = line.trim();
417
- if (line) {
418
- mmf.parseLine(line);
419
- }
420
- }
421
- });
71
+ export async function test(filter = "", options: Partial<TestOptions> = {}) {
72
+ let config = readConfig();
73
+ let rootDir = getRootDir();
74
+
75
+ let replicaType =
76
+ options.replica ??
77
+ (config.toolchain?.["pocket-ic"] ? "pocket-ic" : ("dfx" as ReplicaName));
78
+
79
+ if (replicaType === "pocket-ic" && !config.toolchain?.["pocket-ic"]) {
80
+ let dfxVersion = getDfxVersion();
81
+ if (!dfxVersion || new SemVer(dfxVersion).compare("0.24.1") < 0) {
82
+ console.log(
83
+ chalk.red(
84
+ "Please update dfx to the version >=0.24.1 or specify pocket-ic version in mops.toml",
85
+ ),
86
+ );
87
+ process.exit(1);
88
+ } else {
89
+ replicaType = "dfx-pocket-ic";
90
+ }
91
+ }
92
+
93
+ replica.type = replicaType;
94
+ replica.verbose = !!options.verbose;
95
+
96
+ if (options.watch) {
97
+ replica.ttl = 60 * 15; // 15 minutes
98
+
99
+ let sigint = false;
100
+ process.on("SIGINT", () => {
101
+ if (sigint) {
102
+ console.log("Force exit");
103
+ process.exit(0);
104
+ }
105
+ sigint = true;
106
+
107
+ if (replicaStartPromise) {
108
+ console.log("Stopping replica...");
109
+ replica.stop(true).then(() => {
110
+ process.exit(0);
111
+ });
112
+ } else {
113
+ process.exit(0);
114
+ }
115
+ });
116
+
117
+ // todo: run only changed for *.test.mo?
118
+ // todo: run all for *.mo?
119
+
120
+ let curRun = Promise.resolve(true);
121
+ let controller = new AbortController();
122
+
123
+ let run = debounce(async () => {
124
+ controller.abort();
125
+ await curRun;
126
+
127
+ console.clear();
128
+ process.stdout.write("\x1Bc");
129
+
130
+ controller = new AbortController();
131
+ curRun = runAll(
132
+ options.reporter,
133
+ filter,
134
+ options.mode,
135
+ replicaType,
136
+ true,
137
+ controller.signal,
138
+ );
139
+ await curRun;
140
+
141
+ console.log("-".repeat(50));
142
+ console.log("Waiting for file changes...");
143
+ console.log(chalk.gray(`Press ${chalk.gray("Ctrl+C")} to exit.`));
144
+ }, 200);
145
+
146
+ let watcher = chokidar.watch(
147
+ [path.join(rootDir, "**/*.mo"), path.join(rootDir, "mops.toml")],
148
+ {
149
+ ignored: ignore,
150
+ ignoreInitial: true,
151
+ },
152
+ );
153
+
154
+ watcher.on("all", () => {
155
+ run();
156
+ });
157
+ run();
158
+ } else {
159
+ let passed = await runAll(
160
+ options.reporter,
161
+ filter,
162
+ options.mode,
163
+ replicaType,
164
+ );
165
+ if (!passed) {
166
+ process.exit(1);
167
+ }
168
+ }
422
169
  }
423
170
 
424
- function pipeStderrToMMF(stderr : Readable, mmf : MMF1, dir = '') {
425
- stderr.on('data', (data) => {
426
- let text : string = data.toString().trim();
427
- let failedLine = '';
428
-
429
- text = text.replace(/([\w+._/-]+):(\d+).(\d+)(-\d+.\d+)/g, (_m0, m1 : string, m2 : string, m3 : string) => {
430
- // change absolute file path to relative
431
- // change :line:col-line:col to :line:col to work in vscode
432
- let res = `${absToRel(m1)}:${m2}:${m3}`;
433
- let file = path.join(dir, m1);
434
-
435
- if (!fs.existsSync(file)) {
436
- return res;
437
- }
438
-
439
- // show failed line
440
- let content = fs.readFileSync(file);
441
- let lines = content.toString().split('\n') || [];
442
-
443
- failedLine += chalk.dim('\n ...');
444
-
445
- let lineBefore = lines[+m2 - 2];
446
- if (lineBefore) {
447
- failedLine += chalk.dim(`\n ${+m2 - 1}\t| ${lineBefore.replaceAll('\t', ' ')}`);
448
- }
449
- failedLine += `\n${chalk.redBright`->`} ${m2}\t| ${lines[+m2 - 1]?.replaceAll('\t', ' ')}`;
450
- if (lines.length > +m2) {
451
- failedLine += chalk.dim(`\n ${+m2 + 1}\t| ${lines[+m2]?.replaceAll('\t', ' ')}`);
452
- }
453
- failedLine += chalk.dim('\n ...');
454
- return res;
455
- });
456
- if (failedLine) {
457
- text += failedLine;
458
- }
459
- mmf.fail(text);
460
- });
171
+ let mocPath = "";
172
+ let wasmtimePath = "";
173
+
174
+ async function runAll(
175
+ reporterName: ReporterName | undefined,
176
+ filter = "",
177
+ mode: TestMode = "interpreter",
178
+ replicaType: ReplicaName,
179
+ watch = false,
180
+ signal?: AbortSignal,
181
+ ): Promise<boolean> {
182
+ let done = await testWithReporter(
183
+ reporterName,
184
+ filter,
185
+ mode,
186
+ replicaType,
187
+ watch,
188
+ signal,
189
+ );
190
+ return done;
461
191
  }
462
192
 
463
- function pipeMMF(proc : ChildProcessWithoutNullStreams, mmf : MMF1) {
464
- return new Promise<void>((resolve) => {
465
- pipeStdoutToMMF(proc.stdout, mmf);
466
- pipeStderrToMMF(proc.stderr, mmf);
467
-
468
- // exit
469
- proc.on('close', (code) => {
470
- if (code === 0) {
471
- mmf.strategy !== 'print' && mmf.pass();
472
- }
473
- else if (code !== 1) {
474
- mmf.fail(`unknown exit code: ${code}`);
475
- }
476
- resolve();
477
- });
478
- });
193
+ export async function testWithReporter(
194
+ reporterName: ReporterName | Reporter | undefined,
195
+ filter = "",
196
+ defaultMode: TestMode = "interpreter",
197
+ replicaType: ReplicaName,
198
+ watch = false,
199
+ signal?: AbortSignal,
200
+ ): Promise<boolean> {
201
+ let rootDir = getRootDir();
202
+ let files: string[] = [];
203
+ let libFiles = globSync("**/test?(s)/lib.mo", globConfig);
204
+ if (libFiles[0]) {
205
+ files = [libFiles[0]];
206
+ } else {
207
+ let globStr = "**/test?(s)/**/*.test.mo";
208
+ if (filter) {
209
+ globStr = `**/test?(s)/**/*${filter}*.mo`;
210
+ }
211
+ files = globSync(path.join(rootDir, globStr), globConfig);
212
+ }
213
+ if (!files.length) {
214
+ if (filter) {
215
+ console.log(`No test files found for filter '${filter}'`);
216
+ return false;
217
+ }
218
+ console.log("No test files found");
219
+ console.log("Put your tests in 'test' directory in *.test.mo files");
220
+ return false;
221
+ }
222
+
223
+ let reporter: Reporter;
224
+
225
+ if (!reporterName || typeof reporterName === "string") {
226
+ if (!reporterName) {
227
+ reporterName = files.length > 1 ? "files" : "verbose";
228
+ }
229
+
230
+ if (reporterName == "compact") {
231
+ reporter = new CompactReporter();
232
+ } else if (reporterName == "files") {
233
+ reporter = new FilesReporter();
234
+ } else if (reporterName == "silent") {
235
+ reporter = new SilentReporter();
236
+ } else {
237
+ reporter = new VerboseReporter();
238
+ }
239
+ } else {
240
+ reporter = reporterName;
241
+ }
242
+
243
+ reporter.addFiles(files);
244
+
245
+ let config = readConfig();
246
+ let sourcesArr = await sources();
247
+
248
+ if (!mocPath) {
249
+ mocPath = await toolchain.bin("moc", { fallback: true });
250
+ }
251
+
252
+ let testTempDir = path.join(getRootDir(), ".mops/.test/");
253
+ replica.dir = testTempDir;
254
+
255
+ fs.rmSync(testTempDir, { recursive: true, force: true });
256
+ fs.mkdirSync(testTempDir, { recursive: true });
257
+
258
+ let filesWithMode = files.map((file) => {
259
+ let lines = fs.readFileSync(file, "utf8").split("\n");
260
+ let mode = defaultMode;
261
+ if (lines.includes("// @testmode wasi")) {
262
+ mode = "wasi";
263
+ } else if (
264
+ lines.includes("// @testmode replica") ||
265
+ lines.find((line) => line.match(/^(persistent )?actor( class)?/))
266
+ ) {
267
+ mode = "replica";
268
+ }
269
+ return { file, mode };
270
+ });
271
+
272
+ let hasWasiTests = filesWithMode.some(({ mode }) => mode === "wasi");
273
+ let hasReplicaTests = filesWithMode.some(({ mode }) => mode === "replica");
274
+
275
+ // prepare wasmtime path
276
+ if (hasWasiTests && !wasmtimePath) {
277
+ // ensure wasmtime is installed or specified in config
278
+ if (config.toolchain?.wasmtime) {
279
+ wasmtimePath = await toolchain.bin("wasmtime");
280
+ }
281
+ // fallback wasmtime to global binary if not specified in config (legacy)
282
+ else {
283
+ wasmtimePath = "wasmtime";
284
+ console.log(
285
+ chalk.yellow("Warning:"),
286
+ 'Wasmtime is not specified in config. Using global binary "wasmtime". This will be removed in the future.',
287
+ );
288
+ console.log(
289
+ `Run ${chalk.green("mops toolchain use wasmtime")} or add ${chalk.green('wasmtime = "<version>"')} in mops.toml to avoid breaking changes with future versions of mops.`,
290
+ );
291
+ }
292
+ }
293
+
294
+ let runTestFile = async ({
295
+ file,
296
+ mode,
297
+ }: {
298
+ file: string;
299
+ mode: TestMode;
300
+ }) => {
301
+ if (signal?.aborted) {
302
+ return;
303
+ }
304
+
305
+ // print logs immediately for replica tests because we run them one-by-one
306
+ let mmf = new MMF1(mode === "replica" ? "print" : "store", absToRel(file));
307
+
308
+ let promise = new Promise<void>((resolve) => {
309
+ let mocArgs = [
310
+ "--hide-warnings",
311
+ "--error-detail=2",
312
+ ...sourcesArr.join(" ").split(" "),
313
+ file,
314
+ ].filter((x) => x);
315
+
316
+ // interpret
317
+ if (mode === "interpreter") {
318
+ let proc = spawn(mocPath, ["-r", "-ref-system-api", ...mocArgs], {
319
+ signal,
320
+ });
321
+ proc.addListener("error", (error: any) => {
322
+ if (error?.code === "ABORT_ERR") {
323
+ return;
324
+ }
325
+ throw error;
326
+ });
327
+ pipeMMF(proc, mmf).then(resolve);
328
+ }
329
+ // build and run wasm
330
+ else if (mode === "wasi") {
331
+ let wasmFile = `${path.join(testTempDir, path.parse(file).name)}.wasm`;
332
+
333
+ // build
334
+ let buildProc = spawn(
335
+ mocPath,
336
+ [`-o=${wasmFile}`, "-wasi-system-api", ...mocArgs],
337
+ { signal },
338
+ );
339
+ buildProc.addListener("error", (error: any) => {
340
+ if (error?.code === "ABORT_ERR") {
341
+ return;
342
+ }
343
+ throw error;
344
+ });
345
+ pipeMMF(buildProc, mmf)
346
+ .then(async () => {
347
+ if (mmf.failed > 0) {
348
+ return;
349
+ }
350
+ // run
351
+ let wasmtimeArgs = [];
352
+ if (
353
+ config.toolchain?.wasmtime &&
354
+ config.toolchain?.wasmtime >= "14.0.0"
355
+ ) {
356
+ wasmtimeArgs = [
357
+ "-S",
358
+ "preview2=n",
359
+ "-C",
360
+ "cache=n",
361
+ "-W",
362
+ "bulk-memory",
363
+ "-W",
364
+ "multi-memory",
365
+ "-W",
366
+ "memory64",
367
+ "-W",
368
+ "max-wasm-stack=4000000",
369
+ "-W",
370
+ "nan-canonicalization=y",
371
+ wasmFile,
372
+ ];
373
+ } else {
374
+ console.error(
375
+ chalk.red(
376
+ "Minimum wasmtime version is 14.0.0. Please update wasmtime to the latest version",
377
+ ),
378
+ );
379
+ process.exit(1);
380
+ }
381
+
382
+ let proc = spawn(wasmtimePath, wasmtimeArgs, { signal });
383
+ proc.addListener("error", (error: any) => {
384
+ if (error?.code === "ABORT_ERR") {
385
+ return;
386
+ }
387
+ throw error;
388
+ });
389
+
390
+ await pipeMMF(proc, mmf);
391
+ })
392
+ .finally(() => {
393
+ fs.rmSync(wasmFile, { force: true });
394
+ })
395
+ .then(resolve);
396
+ }
397
+ // build and execute in replica
398
+ else if (mode === "replica") {
399
+ let wasmFile = `${path.join(testTempDir, path.parse(file).name)}.wasm`;
400
+
401
+ // build
402
+ let buildProc = spawn(mocPath, [`-o=${wasmFile}`, ...mocArgs], {
403
+ signal,
404
+ });
405
+ buildProc.addListener("error", (error: any) => {
406
+ if (error?.code === "ABORT_ERR") {
407
+ return;
408
+ }
409
+ throw error;
410
+ });
411
+
412
+ pipeMMF(buildProc, mmf)
413
+ .then(async () => {
414
+ if (mmf.failed > 0) {
415
+ return;
416
+ }
417
+
418
+ await startReplicaOnce(replica, replicaType);
419
+
420
+ if (signal?.aborted) {
421
+ return;
422
+ }
423
+
424
+ let canisterName = path.parse(file).name;
425
+ let idlFactory = ({ IDL }: any) => {
426
+ return IDL.Service({ runTests: IDL.Func([], [], []) });
427
+ };
428
+ interface _SERVICE {
429
+ runTests: ActorMethod<[], undefined>;
430
+ }
431
+
432
+ let canister = await replica.deploy(
433
+ canisterName,
434
+ wasmFile,
435
+ idlFactory,
436
+ undefined,
437
+ signal,
438
+ );
439
+
440
+ if (signal?.aborted || !canister) {
441
+ return;
442
+ }
443
+
444
+ pipeStdoutToMMF(canister.stream, mmf);
445
+
446
+ let actor = (await replica.getActor(canisterName)) as _SERVICE;
447
+
448
+ try {
449
+ if (globalThis.mopsReplicaTestRunning) {
450
+ await new Promise<void>((resolve) => {
451
+ let timerId = setInterval(
452
+ () => {
453
+ if (!globalThis.mopsReplicaTestRunning) {
454
+ resolve();
455
+ clearInterval(timerId);
456
+ }
457
+ },
458
+ (Math.random() * 1000) | 0,
459
+ );
460
+ });
461
+ }
462
+
463
+ if (signal?.aborted) {
464
+ return;
465
+ }
466
+
467
+ globalThis.mopsReplicaTestRunning = true;
468
+ await actor.runTests();
469
+ globalThis.mopsReplicaTestRunning = false;
470
+
471
+ mmf.pass();
472
+ } catch (e: any) {
473
+ let stderrStream = new PassThrough();
474
+ pipeStderrToMMF(stderrStream, mmf, path.dirname(file));
475
+ stderrStream.write(e.message);
476
+ }
477
+ })
478
+ .finally(async () => {
479
+ globalThis.mopsReplicaTestRunning = false;
480
+ fs.rmSync(wasmFile, { force: true });
481
+ })
482
+ .then(resolve);
483
+ }
484
+ });
485
+
486
+ if (signal?.aborted) {
487
+ return;
488
+ }
489
+
490
+ reporter.addRun(file, mmf, promise, mode);
491
+
492
+ await promise;
493
+ };
494
+
495
+ await parallel(
496
+ os.cpus().length,
497
+ filesWithMode.filter(({ mode }) => mode !== "replica"),
498
+ runTestFile,
499
+ );
500
+ await parallel(
501
+ 1,
502
+ filesWithMode.filter(({ mode }) => mode === "replica"),
503
+ runTestFile,
504
+ );
505
+
506
+ if (hasReplicaTests && !watch) {
507
+ await replica.stop();
508
+ fs.rmSync(testTempDir, { recursive: true, force: true });
509
+ }
510
+
511
+ if (signal?.aborted) {
512
+ return false;
513
+ }
514
+
515
+ return reporter.done();
479
516
  }