ic-mops 2.13.1 → 2.14.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 (90) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/bun.lock +24 -12
  3. package/bundle/cli.tgz +0 -0
  4. package/cache.ts +101 -20
  5. package/cli.ts +40 -14
  6. package/commands/available-updates.ts +4 -2
  7. package/commands/bench.ts +3 -0
  8. package/commands/check-stable.ts +27 -23
  9. package/commands/check.ts +11 -1
  10. package/commands/init.ts +15 -2
  11. package/commands/install/install-mops-dep.ts +14 -9
  12. package/commands/install/sync-local-cache.ts +7 -1
  13. package/commands/lint.ts +11 -0
  14. package/commands/outdated.ts +5 -2
  15. package/commands/publish.ts +0 -1
  16. package/commands/test/test.ts +14 -0
  17. package/commands/update.ts +3 -2
  18. package/commands/watch/tester.ts +5 -1
  19. package/dist/cache.d.ts +3 -0
  20. package/dist/cache.js +98 -18
  21. package/dist/cli.js +16 -12
  22. package/dist/commands/available-updates.d.ts +1 -1
  23. package/dist/commands/available-updates.js +4 -1
  24. package/dist/commands/bench.js +2 -0
  25. package/dist/commands/check-stable.d.ts +0 -1
  26. package/dist/commands/check-stable.js +21 -18
  27. package/dist/commands/check.js +7 -1
  28. package/dist/commands/init.js +9 -2
  29. package/dist/commands/install/install-mops-dep.js +12 -9
  30. package/dist/commands/install/sync-local-cache.js +2 -1
  31. package/dist/commands/lint.js +7 -0
  32. package/dist/commands/outdated.d.ts +2 -1
  33. package/dist/commands/outdated.js +2 -2
  34. package/dist/commands/publish.js +0 -1
  35. package/dist/commands/test/test.d.ts +1 -1
  36. package/dist/commands/test/test.js +10 -5
  37. package/dist/commands/update.d.ts +2 -1
  38. package/dist/commands/update.js +2 -2
  39. package/dist/commands/watch/tester.js +4 -1
  40. package/dist/helpers/autofix-motoko.d.ts +1 -1
  41. package/dist/helpers/autofix-motoko.js +3 -0
  42. package/dist/helpers/deprecate-dfx-replica.d.ts +2 -0
  43. package/dist/helpers/deprecate-dfx-replica.js +20 -0
  44. package/dist/helpers/fix-lock.d.ts +1 -0
  45. package/dist/helpers/fix-lock.js +93 -0
  46. package/dist/helpers/migrations.js +7 -5
  47. package/dist/integrity.d.ts +2 -2
  48. package/dist/integrity.js +22 -6
  49. package/dist/mops.js +1 -1
  50. package/dist/package.json +3 -3
  51. package/dist/tests/check-fix.test.js +40 -0
  52. package/dist/tests/check-stable.test.js +17 -0
  53. package/dist/tests/check.test.js +4 -3
  54. package/dist/tests/cli.test.js +136 -1
  55. package/dist/tests/helpers.js +5 -1
  56. package/dist/tests/migrate.test.js +2 -2
  57. package/dist/types.d.ts +1 -0
  58. package/dist/vessel.js +21 -13
  59. package/dist/wasm/pkg/nodejs/package.json +1 -1
  60. package/dist/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
  61. package/dist/wasm/pkg/web/package.json +1 -1
  62. package/dist/wasm/pkg/web/wasm_bg.wasm +0 -0
  63. package/helpers/autofix-motoko.ts +4 -1
  64. package/helpers/deprecate-dfx-replica.ts +32 -0
  65. package/helpers/fix-lock.ts +101 -0
  66. package/helpers/migrations.ts +7 -4
  67. package/integrity.ts +30 -9
  68. package/mops.ts +1 -1
  69. package/package.json +3 -3
  70. package/tests/__snapshots__/migrate.test.ts.snap +1 -2
  71. package/tests/check-fix.test.ts +46 -0
  72. package/tests/check-stable/migrations-chain/deployed.most +14 -0
  73. package/tests/check-stable/migrations-chain/migrations/20250101_000000_Init.mo +8 -0
  74. package/tests/check-stable/migrations-chain/migrations/20250201_000000_AddField.mo +9 -0
  75. package/tests/check-stable/migrations-chain/migrations/20250301_000000_AddD.mo +10 -0
  76. package/tests/check-stable/migrations-chain/migrations/20250401_000000_AddE.mo +11 -0
  77. package/tests/check-stable/migrations-chain/mops.toml +15 -0
  78. package/tests/check-stable/migrations-chain/src/main.mo +13 -0
  79. package/tests/check-stable.test.ts +20 -0
  80. package/tests/check.test.ts +4 -3
  81. package/tests/cli.test.ts +180 -1
  82. package/tests/helpers.ts +5 -1
  83. package/tests/install/update-bound-patch/mops.toml +2 -0
  84. package/tests/migrate.test.ts +2 -2
  85. package/types.ts +1 -0
  86. package/vessel.ts +31 -14
  87. package/wasm/pkg/nodejs/package.json +1 -1
  88. package/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
  89. package/wasm/pkg/web/package.json +1 -1
  90. package/wasm/pkg/web/wasm_bg.wasm +0 -0
package/commands/check.ts CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  resolveConfigPath,
10
10
  } from "../mops.js";
11
11
  import { AutofixResult, autofixMotoko } from "../helpers/autofix-motoko.js";
12
+ import { withFixLock } from "../helpers/fix-lock.js";
12
13
  import { getMocSemVer } from "../helpers/get-moc-version.js";
13
14
  import {
14
15
  filterCanisters,
@@ -82,6 +83,16 @@ function logAutofixResult(
82
83
  export async function check(
83
84
  args: string[],
84
85
  options: Partial<CheckOptions> = {},
86
+ ): Promise<void> {
87
+ if (options.fix) {
88
+ return withFixLock(() => checkImpl(args, options));
89
+ }
90
+ return checkImpl(args, options);
91
+ }
92
+
93
+ async function checkImpl(
94
+ args: string[],
95
+ options: Partial<CheckOptions> = {},
85
96
  ): Promise<void> {
86
97
  const config = readConfig();
87
98
  const canisters = resolveCanisterConfigs(config);
@@ -216,7 +227,6 @@ async function checkCanisters(
216
227
  canisterArgs: [...migration.migrationArgs, ...(canister.args ?? [])],
217
228
  sources,
218
229
  options: { verbose: options.verbose, extraArgs: options.extraArgs },
219
- hasMigrations: !!canister.migrations,
220
230
  });
221
231
  }
222
232
  } finally {
package/commands/init.ts CHANGED
@@ -25,6 +25,20 @@ export async function init({ yes = false } = {}) {
25
25
 
26
26
  let config: Config = {};
27
27
 
28
+ let vesselFile = path.join(process.cwd(), "vessel.dhall");
29
+ let vesselExists = existsSync(vesselFile);
30
+
31
+ // Warn before the --yes early-return so scripted/CI users get the heads-up
32
+ // even though `mops init --yes` skips the vessel migration entirely.
33
+ if (vesselExists) {
34
+ console.warn(
35
+ chalk.yellow(
36
+ "WARN: vessel.dhall auto-migration is deprecated and will be removed in mops v3. " +
37
+ "Before then, copy your dependencies into mops.toml manually and delete vessel.dhall / package-set.dhall.",
38
+ ),
39
+ );
40
+ }
41
+
28
42
  if (yes) {
29
43
  await applyInit({
30
44
  type: "project",
@@ -37,10 +51,9 @@ export async function init({ yes = false } = {}) {
37
51
  }
38
52
 
39
53
  // migrate from vessel
40
- let vesselFile = path.join(process.cwd(), "vessel.dhall");
41
54
  let vesselConfig: VesselConfig = { dependencies: [], "dev-dependencies": [] };
42
55
 
43
- if (existsSync(vesselFile)) {
56
+ if (vesselExists) {
44
57
  console.log("Reading vessel.dhall file");
45
58
  let res = await readVesselConfig(process.cwd(), { cache: false });
46
59
  if (res) {
@@ -4,15 +4,17 @@ import path from "node:path";
4
4
  import { Buffer } from "node:buffer";
5
5
  import { createLogUpdate } from "log-update";
6
6
  import chalk from "chalk";
7
- import { deleteSync } from "del";
8
7
  import { checkConfigFile, progressBar, readConfig } from "../../mops.js";
9
8
  import { getHighestVersion } from "../../api/getHighestVersion.js";
10
9
  import { storageActor } from "../../api/actors.js";
11
10
  import { parallel } from "../../parallel.js";
12
11
  import {
12
+ commitStagingDir,
13
+ createStagingDir,
13
14
  getDepCacheDir,
14
15
  getMopsDepCacheName,
15
16
  isDepCached,
17
+ sweepStaleStagingDirs,
16
18
  } from "../../cache.js";
17
19
  import {
18
20
  downloadFile,
@@ -69,6 +71,8 @@ export async function installMopsDep(
69
71
  version = versionRes.ok;
70
72
  }
71
73
 
74
+ sweepStaleStagingDirs();
75
+
72
76
  let cacheName = getMopsDepCacheName(depName, version);
73
77
  let cacheDir = getDepCacheDir(cacheName);
74
78
 
@@ -100,33 +104,34 @@ export async function installMopsDep(
100
104
  progress();
101
105
  });
102
106
 
107
+ let stagingDir = createStagingDir(cacheDir);
103
108
  let onSigInt = () => {
104
- deleteSync([cacheDir], { force: true });
105
- process.exit();
109
+ fs.rmSync(stagingDir, { recursive: true, force: true });
110
+ process.exit(130);
106
111
  };
107
112
  process.on("SIGINT", onSigInt);
108
113
 
109
- // write files to global cache
110
114
  try {
111
115
  await Promise.all(
112
116
  Array.from(filesData.entries()).map(async ([filePath, data]) => {
113
117
  await fs.promises.mkdir(
114
- path.join(cacheDir, path.dirname(filePath)),
118
+ path.join(stagingDir, path.dirname(filePath)),
115
119
  { recursive: true },
116
120
  );
117
121
  await fs.promises.writeFile(
118
- path.join(cacheDir, filePath),
122
+ path.join(stagingDir, filePath),
119
123
  Buffer.from(data),
120
124
  );
121
125
  }),
122
126
  );
127
+ commitStagingDir(stagingDir, cacheDir);
123
128
  } catch (err) {
124
129
  console.error(chalk.red("Error: ") + err);
125
- deleteSync([cacheDir], { force: true });
130
+ fs.rmSync(stagingDir, { recursive: true, force: true });
126
131
  return false;
132
+ } finally {
133
+ process.off("SIGINT", onSigInt);
127
134
  }
128
-
129
- process.off("SIGINT", onSigInt);
130
135
  } catch (err) {
131
136
  console.error(chalk.red("Error: ") + err);
132
137
  return false;
@@ -1,12 +1,18 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import { copyCache, getDepCacheName } from "../../cache.js";
3
+ import {
4
+ copyCache,
5
+ getDepCacheName,
6
+ sweepStaleStagingDirs,
7
+ } from "../../cache.js";
4
8
  import { getDependencyType, getRootDir } from "../../mops.js";
5
9
  import { resolvePackages } from "../../resolve-packages.js";
6
10
 
7
11
  export async function syncLocalCache({ verbose = false } = {}): Promise<
8
12
  Record<string, string>
9
13
  > {
14
+ sweepStaleStagingDirs();
15
+
10
16
  let resolvedPackages = await resolvePackages();
11
17
  let rootDir = getRootDir();
12
18
 
package/commands/lint.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  readConfig,
12
12
  } from "../mops.js";
13
13
  import { resolvePackages } from "../resolve-packages.js";
14
+ import { withFixLock } from "../helpers/fix-lock.js";
14
15
  import { toolchain } from "./toolchain/index.js";
15
16
  import { MOTOKO_GLOB_CONFIG } from "../constants.js";
16
17
  import { existsSync } from "node:fs";
@@ -174,6 +175,16 @@ async function runLintoko(
174
175
  export async function lint(
175
176
  filter: string | undefined,
176
177
  options: Partial<LintOptions>,
178
+ ): Promise<void> {
179
+ if (options.fix) {
180
+ return withFixLock(() => lintImpl(filter, options));
181
+ }
182
+ return lintImpl(filter, options);
183
+ }
184
+
185
+ async function lintImpl(
186
+ filter: string | undefined,
187
+ options: Partial<LintOptions>,
177
188
  ): Promise<void> {
178
189
  let config = readConfig();
179
190
  let rootDir = getRootDir();
@@ -3,7 +3,10 @@ import { checkConfigFile, readConfig } from "../mops.js";
3
3
  import { getAvailableUpdates } from "./available-updates.js";
4
4
  import { getDepName, getDepPinnedVersion } from "../helpers/get-dep-name.js";
5
5
 
6
- export async function outdated({ major }: { major?: boolean } = {}) {
6
+ export async function outdated({
7
+ major,
8
+ patch,
9
+ }: { major?: boolean; patch?: boolean } = {}) {
7
10
  if (!checkConfigFile()) {
8
11
  return;
9
12
  }
@@ -12,7 +15,7 @@ export async function outdated({ major }: { major?: boolean } = {}) {
12
15
  let available = await getAvailableUpdates(
13
16
  config,
14
17
  undefined,
15
- major ? "major" : "caret",
18
+ major ? "major" : patch ? "patch" : "caret",
16
19
  );
17
20
 
18
21
  if (available.length === 0) {
@@ -336,7 +336,6 @@ export async function publish(
336
336
  console.log("Running benchmarks...");
337
337
  try {
338
338
  benchmarks = await bench("", {
339
- replica: config.toolchain?.["pocket-ic"] ? "pocket-ic" : "dfx",
340
339
  gc: "copying",
341
340
  forceGc: true,
342
341
  silent: true,
@@ -32,6 +32,7 @@ import { toolchain } from "../toolchain/index.js";
32
32
  import { Replica } from "../replica.js";
33
33
  import { TestMode } from "../../types.js";
34
34
  import { getDfxVersion } from "../../helpers/get-dfx-version.js";
35
+ import { warnIfDfxReplica } from "../../helpers/deprecate-dfx-replica.js";
35
36
  import { MOTOKO_GLOB_CONFIG, MOTOKO_IGNORE_PATTERNS } from "../../constants.js";
36
37
 
37
38
  type ReporterName = "verbose" | "files" | "compact" | "silent";
@@ -79,6 +80,8 @@ export async function test(filter = "", options: Partial<TestOptions> = {}) {
79
80
  }
80
81
  }
81
82
 
83
+ let explicitReplica = options.replica === "dfx";
84
+
82
85
  replica.type = replicaType;
83
86
  replica.verbose = !!options.verbose;
84
87
 
@@ -124,6 +127,7 @@ export async function test(filter = "", options: Partial<TestOptions> = {}) {
124
127
  replicaType,
125
128
  true,
126
129
  controller.signal,
130
+ explicitReplica,
127
131
  );
128
132
  await curRun;
129
133
 
@@ -150,6 +154,9 @@ export async function test(filter = "", options: Partial<TestOptions> = {}) {
150
154
  filter,
151
155
  options.mode,
152
156
  replicaType,
157
+ false,
158
+ undefined,
159
+ explicitReplica,
153
160
  );
154
161
  if (!passed) {
155
162
  process.exit(1);
@@ -167,6 +174,7 @@ async function runAll(
167
174
  replicaType: ReplicaName,
168
175
  watch = false,
169
176
  signal?: AbortSignal,
177
+ explicitReplica = false,
170
178
  ): Promise<boolean> {
171
179
  let done = await testWithReporter(
172
180
  reporterName,
@@ -175,6 +183,7 @@ async function runAll(
175
183
  replicaType,
176
184
  watch,
177
185
  signal,
186
+ explicitReplica,
178
187
  );
179
188
  return done;
180
189
  }
@@ -186,6 +195,7 @@ export async function testWithReporter(
186
195
  replicaType: ReplicaName,
187
196
  watch = false,
188
197
  signal?: AbortSignal,
198
+ explicitReplica = false,
189
199
  ): Promise<boolean> {
190
200
  let rootDir = getRootDir();
191
201
  let files: string[] = [];
@@ -261,6 +271,10 @@ export async function testWithReporter(
261
271
  let hasWasiTests = filesWithMode.some(({ mode }) => mode === "wasi");
262
272
  let hasReplicaTests = filesWithMode.some(({ mode }) => mode === "replica");
263
273
 
274
+ if (hasReplicaTests) {
275
+ warnIfDfxReplica(replicaType, explicitReplica);
276
+ }
277
+
264
278
  // prepare wasmtime path
265
279
  if (hasWasiTests && !wasmtimePath) {
266
280
  // ensure wasmtime is installed or specified in config
@@ -15,11 +15,12 @@ type UpdateOptions = {
15
15
  dev?: boolean;
16
16
  lock?: "update" | "ignore";
17
17
  major?: boolean;
18
+ patch?: boolean;
18
19
  };
19
20
 
20
21
  export async function update(
21
22
  pkg?: string,
22
- { lock, major }: UpdateOptions = {},
23
+ { lock, major, patch }: UpdateOptions = {},
23
24
  ) {
24
25
  if (!checkConfigFile()) {
25
26
  return;
@@ -66,7 +67,7 @@ export async function update(
66
67
  let available = await getAvailableUpdates(
67
68
  config,
68
69
  pkg,
69
- major ? "major" : "caret",
70
+ major ? "major" : patch ? "patch" : "caret",
70
71
  );
71
72
 
72
73
  if (available.length === 0) {
@@ -3,6 +3,7 @@ import { readConfig } from "../../mops.js";
3
3
  import { ErrorChecker } from "./error-checker.js";
4
4
  import { testWithReporter } from "../test/test.js";
5
5
  import { SilentReporter } from "../test/reporters/silent-reporter.js";
6
+ import { type ReplicaName } from "../../helpers/deprecate-dfx-replica.js";
6
7
 
7
8
  export class Tester {
8
9
  verbose = false;
@@ -53,12 +54,15 @@ export class Tester {
53
54
  this.controller = new AbortController();
54
55
 
55
56
  let config = readConfig();
57
+ let replicaType: ReplicaName = config.toolchain?.["pocket-ic"]
58
+ ? "pocket-ic"
59
+ : "dfx";
56
60
 
57
61
  this.currentRun = testWithReporter(
58
62
  this.reporter,
59
63
  "",
60
64
  "interpreter",
61
- config.toolchain?.["pocket-ic"] ? "pocket-ic" : "dfx",
65
+ replicaType,
62
66
  true,
63
67
  this.controller.signal,
64
68
  );
package/dist/cache.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ export declare function createStagingDir(dest: string): string;
2
+ export declare function commitStagingDir(staging: string, dest: string): boolean;
3
+ export declare function sweepStaleStagingDirs(): void;
1
4
  export declare let show: () => string;
2
5
  export declare let getDepCacheDir: (cacheName: string) => string;
3
6
  export declare let isDepCached: (cacheName: string) => boolean;
package/dist/cache.js CHANGED
@@ -8,6 +8,72 @@ let getGlobalCacheDir = () => {
8
8
  let network = getNetwork();
9
9
  return path.join(globalCacheDir, network === "ic" ? "" : network);
10
10
  };
11
+ // Cache writes stage into a sibling `<dest>/../.staging-<rand>` and atomic-
12
+ // rename onto `dest` so concurrent processes never observe a partial cache.
13
+ const STAGING_PREFIX = ".staging-";
14
+ export function createStagingDir(dest) {
15
+ let parent = path.dirname(dest);
16
+ fs.mkdirSync(parent, { recursive: true });
17
+ return fs.mkdtempSync(path.join(parent, STAGING_PREFIX));
18
+ }
19
+ // Returns false if another process committed first (race lost) — `staging`
20
+ // is removed and the existing `dest` is left intact. We only swallow
21
+ // `EPERM` (Windows) when `dest` exists; otherwise it's likely AV / open
22
+ // handles and bubbles up.
23
+ export function commitStagingDir(staging, dest) {
24
+ try {
25
+ fs.renameSync(staging, dest);
26
+ return true;
27
+ }
28
+ catch (err) {
29
+ let raceLost = (err.code === "ENOTEMPTY" ||
30
+ err.code === "EEXIST" ||
31
+ err.code === "EPERM") &&
32
+ fs.existsSync(dest);
33
+ if (raceLost) {
34
+ fs.rmSync(staging, { recursive: true, force: true });
35
+ return false;
36
+ }
37
+ throw err;
38
+ }
39
+ }
40
+ // Sweep leftover `.staging-*` from interrupted runs. Mtime cutoff avoids
41
+ // clobbering siblings that are mid-staging right now. Runs at most once
42
+ // per process.
43
+ const STAGING_STALE_MS = 60 * 60 * 1000;
44
+ let swept = false;
45
+ export function sweepStaleStagingDirs() {
46
+ if (swept) {
47
+ return;
48
+ }
49
+ swept = true;
50
+ let cutoff = Date.now() - STAGING_STALE_MS;
51
+ let parents = [
52
+ path.join(getGlobalCacheDir(), "packages"),
53
+ path.join(getGlobalCacheDir(), "packages", "_github"),
54
+ path.join(getRootDir(), ".mops"),
55
+ path.join(getRootDir(), ".mops", "_github"),
56
+ ];
57
+ for (let parent of parents) {
58
+ if (!fs.existsSync(parent)) {
59
+ continue;
60
+ }
61
+ for (let entry of fs.readdirSync(parent)) {
62
+ if (!entry.startsWith(STAGING_PREFIX)) {
63
+ continue;
64
+ }
65
+ let full = path.join(parent, entry);
66
+ try {
67
+ if (fs.statSync(full).mtimeMs < cutoff) {
68
+ fs.rmSync(full, { recursive: true, force: true });
69
+ }
70
+ }
71
+ catch {
72
+ // raced with another sweeper; ignore
73
+ }
74
+ }
75
+ }
76
+ }
11
77
  export let show = () => {
12
78
  return getGlobalCacheDir();
13
79
  };
@@ -32,29 +98,43 @@ export function getGithubDepCacheName(name, repo) {
32
98
  return (`_github/${name}#${branch.replaceAll("/", "___")}` +
33
99
  (commitHash ? `@${commitHash}` : ""));
34
100
  }
35
- export let addCache = (cacheName, source) => {
101
+ export let addCache = async (cacheName, source) => {
36
102
  let dest = path.join(getGlobalCacheDir(), "packages", cacheName);
37
- fs.mkdirSync(dest, { recursive: true });
38
- return new Promise((resolve, reject) => {
39
- ncp.ncp(source, dest, { stopOnErr: true }, (err) => {
40
- if (err) {
41
- reject(err);
42
- }
43
- resolve();
103
+ let staging = createStagingDir(dest);
104
+ try {
105
+ await new Promise((resolve, reject) => {
106
+ ncp.ncp(source, staging, { stopOnErr: true }, (err) => {
107
+ if (err) {
108
+ reject(err);
109
+ }
110
+ resolve();
111
+ });
44
112
  });
45
- });
113
+ commitStagingDir(staging, dest);
114
+ }
115
+ catch (err) {
116
+ fs.rmSync(staging, { recursive: true, force: true });
117
+ throw err;
118
+ }
46
119
  };
47
- export let copyCache = (cacheName, dest) => {
120
+ export let copyCache = async (cacheName, dest) => {
48
121
  let source = path.join(getGlobalCacheDir(), "packages", cacheName);
49
- fs.mkdirSync(dest, { recursive: true });
50
- return new Promise((resolve, reject) => {
51
- ncp.ncp(source, dest, { stopOnErr: true }, (err) => {
52
- if (err) {
53
- reject(err);
54
- }
55
- resolve();
122
+ let staging = createStagingDir(dest);
123
+ try {
124
+ await new Promise((resolve, reject) => {
125
+ ncp.ncp(source, staging, { stopOnErr: true }, (err) => {
126
+ if (err) {
127
+ reject(err);
128
+ }
129
+ resolve();
130
+ });
56
131
  });
57
- });
132
+ commitStagingDir(staging, dest);
133
+ }
134
+ catch (err) {
135
+ fs.rmSync(staging, { recursive: true, force: true });
136
+ throw err;
137
+ }
58
138
  };
59
139
  export let cacheSize = async () => {
60
140
  let dir = path.join(getGlobalCacheDir());
package/dist/cli.js CHANGED
@@ -327,7 +327,7 @@ program
327
327
  .addOption(new Option("--mode <mode>", "Test mode")
328
328
  .choices(["interpreter", "wasi", "replica"])
329
329
  .default("interpreter"))
330
- .addOption(new Option("--replica <replica>", "Which replica to use to run tests in replica mode").choices(["dfx", "pocket-ic"]))
330
+ .addOption(new Option("--replica <replica>", "Which replica to use to run tests in replica mode (`dfx` is deprecated; prefer `pocket-ic`)").choices(["dfx", "pocket-ic"]))
331
331
  .option("-w, --watch", "Enable watch mode")
332
332
  .option("--verbose", "Verbose output")
333
333
  .action(async (filter, options) => {
@@ -343,7 +343,7 @@ program
343
343
  program
344
344
  .command("bench [filter]")
345
345
  .description("Run benchmarks")
346
- .addOption(new Option("--replica <replica>", "Which replica to use to run benchmarks").choices(["dfx", "pocket-ic"]))
346
+ .addOption(new Option("--replica <replica>", "Which replica to use to run benchmarks (`dfx` is deprecated; prefer `pocket-ic`)").choices(["dfx", "pocket-ic"]))
347
347
  .addOption(new Option("--gc <gc>", "Garbage collector")
348
348
  .choices(["copying", "compacting", "generational", "incremental"])
349
349
  .default("copying"))
@@ -491,16 +491,18 @@ program
491
491
  // outdated
492
492
  program
493
493
  .command("outdated")
494
- .description("Print outdated dependencies specified in mops.toml")
495
- .addOption(new Option("--major", "Allow updates that cross the caret bound (major versions, or for 0.x.y packages, minor versions)"))
494
+ .description("Print outdated dependencies in mops.toml within the caret bound (does not cross major versions, or pre-1.0 minor versions)")
495
+ .addOption(new Option("--major", "Allow updates that cross the caret bound (major versions, or for 0.x.y packages, minor versions)").conflicts("patch"))
496
+ .addOption(new Option("--patch", "Restrict updates to patch versions only (e.g. 1.2.3 -> 1.2.4, never 1.2.3 -> 1.3.0)"))
496
497
  .action(async (options) => {
497
498
  await outdated(options);
498
499
  });
499
500
  // update
500
501
  program
501
502
  .command("update [pkg]")
502
- .description("Update dependencies specified in mops.toml")
503
- .addOption(new Option("--major", "Allow updates that cross the caret bound (major versions, or for 0.x.y packages, minor versions)"))
503
+ .description("Update dependencies in mops.toml to the highest semver-compatible version within the caret bound (does not cross major versions, or pre-1.0 minor versions)")
504
+ .addOption(new Option("--major", "Allow updates that cross the caret bound (major versions, or for 0.x.y packages, minor versions)").conflicts("patch"))
505
+ .addOption(new Option("--patch", "Restrict updates to patch versions only (e.g. 1.2.3 -> 1.2.4, never 1.2.3 -> 1.3.0)"))
504
506
  .addOption(new Option("--lock <action>", "Lockfile action").choices([
505
507
  "update",
506
508
  "ignore",
@@ -509,7 +511,9 @@ program
509
511
  await update(pkg, options);
510
512
  });
511
513
  // toolchain
512
- const toolchainCommand = new Command("toolchain").description("Toolchain management");
514
+ const toolchainCommand = new Command("toolchain")
515
+ .description(`Toolchain management for ${TOOLCHAINS.map((s) => `"${s}"`).join(", ")}`)
516
+ .showHelpAfterError();
513
517
  toolchainCommand
514
518
  .command("init")
515
519
  .description("One-time initialization of toolchain management")
@@ -525,8 +529,8 @@ toolchainCommand
525
529
  toolchainCommand
526
530
  .command("use")
527
531
  .description("Install specified tool version and update mops.toml")
528
- .addArgument(new Argument("<tool>").choices(TOOLCHAINS))
529
- .addArgument(new Argument("[version]"))
532
+ .addArgument(new Argument("<tool>", "tool to install").choices(TOOLCHAINS))
533
+ .addArgument(new Argument("[version]", "version to install (defaults to interactive picker)"))
530
534
  .action(async (tool, version) => {
531
535
  if (!checkConfigFile()) {
532
536
  process.exit(1);
@@ -536,7 +540,7 @@ toolchainCommand
536
540
  toolchainCommand
537
541
  .command("update")
538
542
  .description("Update specified tool or all tools to the latest version and update mops.toml")
539
- .addArgument(new Argument("[tool]").choices(TOOLCHAINS))
543
+ .addArgument(new Argument("[tool]", "tool to update (defaults to all configured tools)").choices(TOOLCHAINS))
540
544
  .action(async (tool) => {
541
545
  if (!checkConfigFile()) {
542
546
  process.exit(1);
@@ -545,8 +549,8 @@ toolchainCommand
545
549
  });
546
550
  toolchainCommand
547
551
  .command("bin")
548
- .description(`Get path to the tool binary\n<tool> can be one of ${TOOLCHAINS.map((s) => `"${s}"`).join(", ")}`)
549
- .addArgument(new Argument("<tool>").choices(TOOLCHAINS))
552
+ .description("Get path to the tool binary")
553
+ .addArgument(new Argument("<tool>", "tool to look up").choices(TOOLCHAINS))
550
554
  .addOption(new Option("--fallback", "Fallback to the moc that comes with dfx if moc is not specified in the [toolchain] section"))
551
555
  .action(async (tool, options) => {
552
556
  let bin = await toolchain.bin(tool, options);
@@ -1,3 +1,3 @@
1
1
  import { Config } from "../types.js";
2
- export type UpdateBound = "caret" | "major";
2
+ export type UpdateBound = "patch" | "caret" | "major";
3
3
  export declare function getAvailableUpdates(config: Config, pkg?: string, bound?: UpdateBound): Promise<Array<[string, string, string]>>;
@@ -29,7 +29,10 @@ export async function getAvailableUpdates(config, pkg, bound = "caret") {
29
29
  let semverPart = { major: null };
30
30
  let name = getDepName(dep.name);
31
31
  let pinnedVersion = getDepPinnedVersion(dep.name);
32
- if (pinnedVersion) {
32
+ if (bound === "patch") {
33
+ semverPart = { patch: null };
34
+ }
35
+ else if (pinnedVersion) {
33
36
  semverPart =
34
37
  pinnedVersion.split(".").length === 1
35
38
  ? { minor: null }
@@ -16,6 +16,7 @@ import { parallel } from "../parallel.js";
16
16
  import { absToRel } from "./test/utils.js";
17
17
  import { getMocVersion } from "../helpers/get-moc-version.js";
18
18
  import { getDfxVersion } from "../helpers/get-dfx-version.js";
19
+ import { warnIfDfxReplica } from "../helpers/deprecate-dfx-replica.js";
19
20
  import { getMocPath } from "../helpers/get-moc-path.js";
20
21
  import { sources } from "./sources.js";
21
22
  import { MOTOKO_GLOB_CONFIG } from "../constants.js";
@@ -59,6 +60,7 @@ export async function bench(filter = "", optionsArg = {}) {
59
60
  else if (replicaType == "pocket-ic") {
60
61
  options.replicaVersion = config.toolchain?.["pocket-ic"] || "";
61
62
  }
63
+ warnIfDfxReplica(replicaType, optionsArg.replica === "dfx");
62
64
  options.verbose && console.log(options);
63
65
  let replica = new BenchReplica(replicaType, options.verbose);
64
66
  let rootDir = getRootDir();
@@ -16,6 +16,5 @@ export interface RunStableCheckParams {
16
16
  canisterArgs: string[];
17
17
  sources?: string[];
18
18
  options?: Partial<CheckStableOptions>;
19
- hasMigrations?: boolean;
20
19
  }
21
20
  export declare function runStableCheck(params: RunStableCheckParams): Promise<void>;