ic-mops 2.9.0 → 2.10.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## Next
4
4
 
5
+ ## 2.10.0
6
+ - `mops check` and `mops check-stable` now apply per-canister `[canisters.<name>].args` (previously only `mops build` applied them)
7
+ - `mops check` now accepts canister names as arguments (e.g. `mops check backend`) to check a specific canister
8
+ - `mops check-stable` now works without arguments, checking all canisters with `[check-stable]` configured
9
+ - `mops check-stable` now accepts canister names as arguments (e.g. `mops check-stable backend`)
10
+
5
11
  ## 2.9.0
6
12
  - Add `mops info <pkg>` command to show detailed package metadata from the registry
7
13
  - Add `[lint.extra]` config for applying additional lint rules to specific files via glob patterns
package/bundle/cli.tgz CHANGED
Binary file
package/cli.ts CHANGED
@@ -330,9 +330,9 @@ program
330
330
 
331
331
  // check
332
332
  program
333
- .command("check [files...]")
333
+ .command("check [args...]")
334
334
  .description(
335
- "Check Motoko files for syntax errors and type issues. If no files are specified, checks all canister entrypoints from mops.toml. Also runs stable compatibility checks for canisters with [check-stable] configured, and runs linting if lintoko is configured in [toolchain] and rule directories are present",
335
+ "Check Motoko canisters or files for syntax errors and type issues. Arguments can be canister names or file paths. If no arguments are given, checks all canisters from mops.toml. Also runs stable compatibility checks for canisters with [check-stable] configured, and runs linting if lintoko is configured in [toolchain]",
336
336
  )
337
337
  .option("--verbose", "Verbose console output")
338
338
  .addOption(
@@ -342,15 +342,15 @@ program
342
342
  ),
343
343
  )
344
344
  .allowUnknownOption(true)
345
- .action(async (files, options) => {
345
+ .action(async (args, options) => {
346
346
  checkConfigFile(true);
347
- const { extraArgs, args: fileList } = parseExtraArgs(files);
347
+ const { extraArgs, args: argList } = parseExtraArgs(args);
348
348
  await installAll({
349
349
  silent: true,
350
350
  lock: "ignore",
351
351
  installFromLockFile: true,
352
352
  });
353
- await check(fileList, {
353
+ await check(argList, {
354
354
  ...options,
355
355
  extraArgs,
356
356
  });
@@ -372,21 +372,21 @@ program
372
372
 
373
373
  // check-stable
374
374
  program
375
- .command("check-stable <old-file> [canister]")
375
+ .command("check-stable [args...]")
376
376
  .description(
377
- "Check stable variable compatibility between an old version (.mo or .most file) and the current canister entrypoint",
377
+ "Check stable variable compatibility. With no arguments, checks all canisters with [check-stable] configured. Arguments can be canister names or an old file path followed by an optional canister name",
378
378
  )
379
379
  .option("--verbose", "Verbose console output")
380
380
  .allowUnknownOption(true)
381
- .action(async (oldFile, canister, options) => {
381
+ .action(async (args, options) => {
382
382
  checkConfigFile(true);
383
- const { extraArgs } = parseExtraArgs();
383
+ const { extraArgs, args: argList } = parseExtraArgs(args);
384
384
  await installAll({
385
385
  silent: true,
386
386
  lock: "ignore",
387
387
  installFromLockFile: true,
388
388
  });
389
- await checkStable(oldFile, canister, {
389
+ await checkStable(argList, {
390
390
  ...options,
391
391
  extraArgs,
392
392
  });
package/commands/build.ts CHANGED
@@ -6,7 +6,11 @@ import { join } from "node:path";
6
6
  import { lock, unlockSync } from "proper-lockfile";
7
7
  import { cliError } from "../error.js";
8
8
  import { isCandidCompatible } from "../helpers/is-candid-compatible.js";
9
- import { resolveCanisterConfigs } from "../helpers/resolve-canisters.js";
9
+ import {
10
+ filterCanisters,
11
+ resolveCanisterConfigs,
12
+ validateCanisterArgs,
13
+ } from "../helpers/resolve-canisters.js";
10
14
  import { CanisterConfig, Config } from "../types.js";
11
15
  import { CustomSection, getWasmBindings } from "../wasm.js";
12
16
  import { getGlobalMocArgs, readConfig, resolveConfigPath } from "../mops.js";
@@ -41,26 +45,11 @@ export async function build(
41
45
  cliError(`No Motoko canisters found in mops.toml configuration`);
42
46
  }
43
47
 
44
- if (canisterNames) {
45
- let invalidNames = canisterNames.filter((name) => !(name in canisters));
46
- if (invalidNames.length) {
47
- cliError(
48
- `Motoko canister(s) not found in mops.toml configuration: ${invalidNames.join(", ")}`,
49
- );
50
- }
51
- }
52
-
53
48
  if (!(await exists(outputDir))) {
54
49
  await mkdir(outputDir, { recursive: true });
55
50
  }
56
51
 
57
- const filteredCanisters = canisterNames
58
- ? Object.fromEntries(
59
- Object.entries(canisters).filter(([name]) =>
60
- canisterNames.includes(name),
61
- ),
62
- )
63
- : canisters;
52
+ const filteredCanisters = filterCanisters(canisters, canisterNames);
64
53
 
65
54
  for (let [canisterName, canister] of Object.entries(filteredCanisters)) {
66
55
  console.log(chalk.blue("build canister"), chalk.bold(canisterName));
@@ -249,11 +238,7 @@ function collectExtraArgs(
249
238
  args.push(...config.build.args);
250
239
  }
251
240
  if (canister.args) {
252
- if (typeof canister.args === "string") {
253
- cliError(
254
- `Canister config 'args' should be an array of strings for canister ${canisterName}`,
255
- );
256
- }
241
+ validateCanisterArgs(canister, canisterName);
257
242
  args.push(...canister.args);
258
243
  }
259
244
  if (extraArgs) {
@@ -5,7 +5,14 @@ import chalk from "chalk";
5
5
  import { execa } from "execa";
6
6
  import { cliError } from "../error.js";
7
7
  import { getGlobalMocArgs, readConfig, resolveConfigPath } from "../mops.js";
8
- import { resolveSingleCanister } from "../helpers/resolve-canisters.js";
8
+ import { CanisterConfig } from "../types.js";
9
+ import {
10
+ filterCanisters,
11
+ looksLikeFile,
12
+ resolveCanisterConfigs,
13
+ resolveSingleCanister,
14
+ validateCanisterArgs,
15
+ } from "../helpers/resolve-canisters.js";
9
16
  import { sourcesArgs } from "./sources.js";
10
17
  import { toolchain } from "./toolchain/index.js";
11
18
 
@@ -16,29 +23,108 @@ export interface CheckStableOptions {
16
23
  extraArgs: string[];
17
24
  }
18
25
 
26
+ export function resolveStablePath(
27
+ canister: CanisterConfig,
28
+ canisterName: string,
29
+ options?: { required?: boolean },
30
+ ): string | null {
31
+ const stableConfig = canister["check-stable"];
32
+ if (!stableConfig) {
33
+ if (options?.required) {
34
+ cliError(
35
+ `Canister '${canisterName}' has no [canisters.${canisterName}.check-stable] configuration in mops.toml`,
36
+ );
37
+ }
38
+ return null;
39
+ }
40
+ const stablePath = resolveConfigPath(stableConfig.path);
41
+ if (!existsSync(stablePath)) {
42
+ if (stableConfig.skipIfMissing) {
43
+ return null;
44
+ }
45
+ cliError(
46
+ `Deployed file not found: ${stablePath} (canister '${canisterName}')\n` +
47
+ "Set skipIfMissing = true in [canisters." +
48
+ canisterName +
49
+ ".check-stable] to skip this check when the file is missing.",
50
+ );
51
+ }
52
+ return stablePath;
53
+ }
54
+
19
55
  export async function checkStable(
20
- oldFile: string,
21
- canisterName: string | undefined,
56
+ args: string[],
22
57
  options: Partial<CheckStableOptions> = {},
23
58
  ): Promise<void> {
24
59
  const config = readConfig();
25
- const { name, canister } = resolveSingleCanister(config, canisterName);
60
+ const mocPath = await toolchain.bin("moc", { fallback: true });
61
+ const globalMocArgs = getGlobalMocArgs(config);
62
+
63
+ const firstArg = args[0];
64
+ if (firstArg && looksLikeFile(firstArg)) {
65
+ const oldFile = firstArg;
66
+ const canisterName = args[1];
67
+ const { name, canister } = resolveSingleCanister(config, canisterName);
68
+
69
+ if (!canister.main) {
70
+ cliError(`No main file specified for canister '${name}' in mops.toml`);
71
+ }
72
+
73
+ validateCanisterArgs(canister, name);
26
74
 
27
- if (!canister.main) {
28
- cliError(`No main file specified for canister '${name}' in mops.toml`);
75
+ await runStableCheck({
76
+ oldFile,
77
+ canisterMain: resolveConfigPath(canister.main),
78
+ canisterName: name,
79
+ mocPath,
80
+ globalMocArgs,
81
+ canisterArgs: canister.args ?? [],
82
+ options,
83
+ });
84
+ return;
29
85
  }
30
86
 
31
- const mocPath = await toolchain.bin("moc", { fallback: true });
32
- const globalMocArgs = getGlobalMocArgs(config);
87
+ const canisters = resolveCanisterConfigs(config);
88
+ const canisterNames = args.length > 0 ? args : undefined;
89
+ const filteredCanisters = filterCanisters(canisters, canisterNames);
90
+ const sources = (await sourcesArgs()).flat();
33
91
 
34
- await runStableCheck({
35
- oldFile,
36
- canisterMain: resolveConfigPath(canister.main),
37
- canisterName: name,
38
- mocPath,
39
- globalMocArgs,
40
- options,
41
- });
92
+ let checked = 0;
93
+ for (const [name, canister] of Object.entries(filteredCanisters)) {
94
+ if (!canister.main) {
95
+ cliError(`No main file specified for canister '${name}' in mops.toml`);
96
+ }
97
+
98
+ validateCanisterArgs(canister, name);
99
+ const stablePath = resolveStablePath(canister, name, {
100
+ required: !!canisterNames,
101
+ });
102
+ if (!stablePath) {
103
+ continue;
104
+ }
105
+
106
+ await runStableCheck({
107
+ oldFile: stablePath,
108
+ canisterMain: resolveConfigPath(canister.main),
109
+ canisterName: name,
110
+ mocPath,
111
+ globalMocArgs,
112
+ canisterArgs: canister.args ?? [],
113
+ sources,
114
+ options,
115
+ });
116
+ checked++;
117
+ }
118
+
119
+ if (checked === 0 && !canisterNames) {
120
+ cliError(
121
+ "No canisters with [check-stable] configuration found in mops.toml.\n" +
122
+ "Either pass an old file: mops check-stable <old-file> [canister]\n" +
123
+ "Or configure check-stable for a canister:\n\n" +
124
+ " [canisters.backend.check-stable]\n" +
125
+ ' path = "deployed.mo"',
126
+ );
127
+ }
42
128
  }
43
129
 
44
130
  export interface RunStableCheckParams {
@@ -47,6 +133,8 @@ export interface RunStableCheckParams {
47
133
  canisterName: string;
48
134
  mocPath: string;
49
135
  globalMocArgs: string[];
136
+ canisterArgs: string[];
137
+ sources?: string[];
50
138
  options?: Partial<CheckStableOptions>;
51
139
  }
52
140
 
@@ -59,10 +147,11 @@ export async function runStableCheck(
59
147
  canisterName,
60
148
  mocPath,
61
149
  globalMocArgs,
150
+ canisterArgs,
62
151
  options = {},
63
152
  } = params;
64
153
 
65
- const sources = (await sourcesArgs()).flat();
154
+ const sources = params.sources ?? (await sourcesArgs()).flat();
66
155
  const isOldMostFile = oldFile.endsWith(".most");
67
156
 
68
157
  if (!existsSync(oldFile)) {
@@ -80,6 +169,7 @@ export async function runStableCheck(
80
169
  join(CHECK_STABLE_DIR, "old.most"),
81
170
  sources,
82
171
  globalMocArgs,
172
+ canisterArgs,
83
173
  options,
84
174
  );
85
175
 
@@ -89,6 +179,7 @@ export async function runStableCheck(
89
179
  join(CHECK_STABLE_DIR, "new.most"),
90
180
  sources,
91
181
  globalMocArgs,
182
+ canisterArgs,
92
183
  options,
93
184
  );
94
185
 
@@ -134,6 +225,7 @@ async function generateStableTypes(
134
225
  outputPath: string,
135
226
  sources: string[],
136
227
  globalMocArgs: string[],
228
+ canisterArgs: string[],
137
229
  options: Partial<CheckStableOptions>,
138
230
  ): Promise<string> {
139
231
  const base = basename(outputPath, ".most");
@@ -145,6 +237,7 @@ async function generateStableTypes(
145
237
  moFile,
146
238
  ...sources,
147
239
  ...globalMocArgs,
240
+ ...canisterArgs,
148
241
  ...(options.extraArgs ?? []),
149
242
  ];
150
243
 
package/commands/check.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import path from "node:path";
2
- import { existsSync } from "node:fs";
3
2
  import chalk from "chalk";
4
3
  import { execa } from "execa";
5
4
  import { cliError } from "../error.js";
@@ -9,13 +8,16 @@ import {
9
8
  readConfig,
10
9
  resolveConfigPath,
11
10
  } from "../mops.js";
12
- import { autofixMotoko } from "../helpers/autofix-motoko.js";
11
+ import { AutofixResult, autofixMotoko } from "../helpers/autofix-motoko.js";
13
12
  import { getMocSemVer } from "../helpers/get-moc-version.js";
14
13
  import {
14
+ filterCanisters,
15
+ looksLikeFile,
15
16
  resolveCanisterConfigs,
16
- resolveCanisterEntrypoints,
17
+ validateCanisterArgs,
17
18
  } from "../helpers/resolve-canisters.js";
18
- import { runStableCheck } from "./check-stable.js";
19
+ import { CanisterConfig, Config } from "../types.js";
20
+ import { resolveStablePath, runStableCheck } from "./check-stable.js";
19
21
  import { sourcesArgs } from "./sources.js";
20
22
  import { toolchain } from "./toolchain/index.js";
21
23
  import { collectLintRules, lint } from "./lint.js";
@@ -33,52 +35,197 @@ export interface CheckOptions {
33
35
  extraArgs: string[];
34
36
  }
35
37
 
38
+ function checkAllLibsSupport(verbose?: boolean): boolean {
39
+ const allLibs = supportsAllLibsFlag();
40
+ if (!allLibs) {
41
+ console.log(
42
+ chalk.yellow(
43
+ `moc < ${MOC_ALL_LIBS_MIN_VERSION}: some diagnostic hints may be missing`,
44
+ ),
45
+ );
46
+ } else if (verbose) {
47
+ console.log(
48
+ chalk.blue("check"),
49
+ chalk.gray("Using --all-libs for richer diagnostics"),
50
+ );
51
+ }
52
+ return allLibs;
53
+ }
54
+
55
+ function logAutofixResult(
56
+ fixResult: AutofixResult | null,
57
+ verbose?: boolean,
58
+ ): void {
59
+ if (fixResult) {
60
+ for (const [file, codes] of fixResult.fixedFiles) {
61
+ const unique = [...new Set(codes)].sort();
62
+ const n = codes.length;
63
+ const rel = path.relative(process.cwd(), file);
64
+ console.log(
65
+ chalk.green(
66
+ `Fixed ${rel} (${n} ${n === 1 ? "fix" : "fixes"}: ${unique.join(", ")})`,
67
+ ),
68
+ );
69
+ }
70
+ const fileCount = fixResult.fixedFiles.size;
71
+ console.log(
72
+ chalk.green(
73
+ `\n✓ ${fixResult.totalFixCount} ${fixResult.totalFixCount === 1 ? "fix" : "fixes"} applied to ${fileCount} ${fileCount === 1 ? "file" : "files"}`,
74
+ ),
75
+ );
76
+ } else if (verbose) {
77
+ console.log(chalk.yellow("No fixes were needed"));
78
+ }
79
+ }
80
+
36
81
  export async function check(
37
- files: string | string[],
82
+ args: string[],
38
83
  options: Partial<CheckOptions> = {},
39
84
  ): Promise<void> {
40
- const explicitFiles = Array.isArray(files) ? files : files ? [files] : [];
41
- let fileList = [...explicitFiles];
42
-
43
85
  const config = readConfig();
86
+ const canisters = resolveCanisterConfigs(config);
87
+ const hasCanisters = Object.keys(canisters).length > 0;
88
+ const fileArgs = args.filter(looksLikeFile);
89
+ const nonFileArgs = args.filter((a) => !looksLikeFile(a));
90
+ const isFileMode = fileArgs.length > 0;
44
91
 
45
- if (fileList.length === 0) {
46
- fileList = resolveCanisterEntrypoints(config).map(resolveConfigPath);
47
- }
48
-
49
- if (fileList.length === 0) {
92
+ if (isFileMode && nonFileArgs.length > 0) {
50
93
  cliError(
51
- "No Motoko files specified and no canisters defined in mops.toml.\n" +
52
- "Either pass files: mops check <files...>\n" +
53
- "Or define canisters in mops.toml:\n\n" +
54
- " [canisters.backend]\n" +
55
- ' main = "src/main.mo"',
94
+ `Cannot mix file paths and canister names: ${args.join(", ")}\n` +
95
+ "Pass either file paths (e.g. mops check src/main.mo) or canister names (e.g. mops check backend)",
56
96
  );
57
97
  }
98
+
99
+ if (isFileMode) {
100
+ await checkFiles(config, fileArgs, options);
101
+ } else {
102
+ if (!hasCanisters) {
103
+ cliError(
104
+ "No canisters defined in mops.toml.\n" +
105
+ "Either pass files: mops check <files...>\n" +
106
+ "Or define canisters in mops.toml:\n\n" +
107
+ " [canisters.backend]\n" +
108
+ ' main = "src/main.mo"',
109
+ );
110
+ }
111
+
112
+ const canisterNames = args.length > 0 ? args : undefined;
113
+ const filtered = filterCanisters(canisters, canisterNames);
114
+ await checkCanisters(config, filtered, options);
115
+ }
116
+
117
+ if (config.toolchain?.lintoko) {
118
+ const rootDir = getRootDir();
119
+ const lintRules = await collectLintRules(config, rootDir);
120
+ const lintFiles = isFileMode ? fileArgs : undefined;
121
+ await lint(undefined, {
122
+ verbose: options.verbose,
123
+ fix: options.fix,
124
+ rules: lintRules,
125
+ files: lintFiles,
126
+ });
127
+ }
128
+ }
129
+
130
+ async function checkCanisters(
131
+ config: Config,
132
+ canisters: Record<string, CanisterConfig>,
133
+ options: Partial<CheckOptions>,
134
+ ): Promise<void> {
58
135
  const mocPath = await toolchain.bin("moc", { fallback: true });
59
- const sources = await sourcesArgs();
136
+ const sources = (await sourcesArgs()).flat();
60
137
  const globalMocArgs = getGlobalMocArgs(config);
138
+ const allLibs = checkAllLibsSupport(options.verbose);
61
139
 
62
- // --all-libs enables richer diagnostics with edit suggestions from moc (requires moc >= 1.3.0)
63
- const allLibs = supportsAllLibsFlag();
140
+ for (const [canisterName, canister] of Object.entries(canisters)) {
141
+ if (!canister.main) {
142
+ cliError(
143
+ `No main file specified for canister '${canisterName}' in mops.toml`,
144
+ );
145
+ }
64
146
 
65
- if (!allLibs) {
66
- console.log(
67
- chalk.yellow(
68
- `moc < ${MOC_ALL_LIBS_MIN_VERSION}: some diagnostic hints may be missing`,
69
- ),
70
- );
71
- } else if (options.verbose) {
72
- console.log(
73
- chalk.blue("check"),
74
- chalk.gray("Using --all-libs for richer diagnostics"),
75
- );
147
+ validateCanisterArgs(canister, canisterName);
148
+ const motokoPath = resolveConfigPath(canister.main);
149
+
150
+ const mocArgs = [
151
+ "--check",
152
+ ...(allLibs ? ["--all-libs"] : []),
153
+ ...sources,
154
+ ...globalMocArgs,
155
+ ...(canister.args ?? []),
156
+ ...(options.extraArgs ?? []),
157
+ ];
158
+
159
+ if (options.fix) {
160
+ if (options.verbose) {
161
+ console.log(
162
+ chalk.blue("check"),
163
+ chalk.gray(`Attempting to fix ${canisterName}`),
164
+ );
165
+ }
166
+
167
+ const fixResult = await autofixMotoko(mocPath, [motokoPath], mocArgs);
168
+ logAutofixResult(fixResult, options.verbose);
169
+ }
170
+
171
+ try {
172
+ const args = [motokoPath, ...mocArgs];
173
+ if (options.verbose) {
174
+ console.log(
175
+ chalk.blue("check"),
176
+ chalk.gray(`Checking canister ${canisterName}:`),
177
+ );
178
+ console.log(chalk.gray(mocPath, JSON.stringify(args)));
179
+ }
180
+
181
+ const result = await execa(mocPath, args, {
182
+ stdio: "inherit",
183
+ reject: false,
184
+ });
185
+
186
+ if (result.exitCode !== 0) {
187
+ cliError(
188
+ `✗ Check failed for canister ${canisterName} (exit code: ${result.exitCode})`,
189
+ );
190
+ }
191
+
192
+ console.log(chalk.green(`✓ ${canisterName}`));
193
+ } catch (err: any) {
194
+ cliError(
195
+ `Error while checking canister ${canisterName}${err?.message ? `\n${err.message}` : ""}`,
196
+ );
197
+ }
198
+
199
+ const stablePath = resolveStablePath(canister, canisterName);
200
+ if (stablePath) {
201
+ await runStableCheck({
202
+ oldFile: stablePath,
203
+ canisterMain: motokoPath,
204
+ canisterName,
205
+ mocPath,
206
+ globalMocArgs,
207
+ canisterArgs: canister.args ?? [],
208
+ sources,
209
+ options: { verbose: options.verbose, extraArgs: options.extraArgs },
210
+ });
211
+ }
76
212
  }
213
+ }
214
+
215
+ async function checkFiles(
216
+ config: Config,
217
+ files: string[],
218
+ options: Partial<CheckOptions>,
219
+ ): Promise<void> {
220
+ const mocPath = await toolchain.bin("moc", { fallback: true });
221
+ const sources = (await sourcesArgs()).flat();
222
+ const globalMocArgs = getGlobalMocArgs(config);
223
+ const allLibs = checkAllLibsSupport(options.verbose);
77
224
 
78
225
  const mocArgs = [
79
226
  "--check",
80
227
  ...(allLibs ? ["--all-libs"] : []),
81
- ...sources.flat(),
228
+ ...sources,
82
229
  ...globalMocArgs,
83
230
  ...(options.extraArgs ?? []),
84
231
  ];
@@ -88,32 +235,11 @@ export async function check(
88
235
  console.log(chalk.blue("check"), chalk.gray("Attempting to fix files"));
89
236
  }
90
237
 
91
- const fixResult = await autofixMotoko(mocPath, fileList, mocArgs);
92
- if (fixResult) {
93
- for (const [file, codes] of fixResult.fixedFiles) {
94
- const unique = [...new Set(codes)].sort();
95
- const n = codes.length;
96
- const rel = path.relative(process.cwd(), file);
97
- console.log(
98
- chalk.green(
99
- `Fixed ${rel} (${n} ${n === 1 ? "fix" : "fixes"}: ${unique.join(", ")})`,
100
- ),
101
- );
102
- }
103
- const fileCount = fixResult.fixedFiles.size;
104
- console.log(
105
- chalk.green(
106
- `\n✓ ${fixResult.totalFixCount} ${fixResult.totalFixCount === 1 ? "fix" : "fixes"} applied to ${fileCount} ${fileCount === 1 ? "file" : "files"}`,
107
- ),
108
- );
109
- } else {
110
- if (options.verbose) {
111
- console.log(chalk.yellow("No fixes were needed"));
112
- }
113
- }
238
+ const fixResult = await autofixMotoko(mocPath, files, mocArgs);
239
+ logAutofixResult(fixResult, options.verbose);
114
240
  }
115
241
 
116
- for (const file of fileList) {
242
+ for (const file of files) {
117
243
  try {
118
244
  const args = [file, ...mocArgs];
119
245
  if (options.verbose) {
@@ -139,49 +265,4 @@ export async function check(
139
265
  );
140
266
  }
141
267
  }
142
-
143
- const canisters = resolveCanisterConfigs(config);
144
- for (const [name, canister] of Object.entries(canisters)) {
145
- const stableConfig = canister["check-stable"];
146
- if (!stableConfig) {
147
- continue;
148
- }
149
-
150
- if (!canister.main) {
151
- cliError(`No main file specified for canister '${name}' in mops.toml`);
152
- }
153
-
154
- const stablePath = resolveConfigPath(stableConfig.path);
155
- if (!existsSync(stablePath)) {
156
- if (stableConfig.skipIfMissing) {
157
- continue;
158
- }
159
- cliError(
160
- `Deployed file not found: ${stablePath} (canister '${name}')\n` +
161
- "Set skipIfMissing = true in [canisters." +
162
- name +
163
- ".check-stable] to skip this check when the file is missing.",
164
- );
165
- }
166
-
167
- await runStableCheck({
168
- oldFile: stablePath,
169
- canisterMain: resolveConfigPath(canister.main),
170
- canisterName: name,
171
- mocPath,
172
- globalMocArgs,
173
- options: { verbose: options.verbose, extraArgs: options.extraArgs },
174
- });
175
- }
176
-
177
- if (config.toolchain?.lintoko) {
178
- const rootDir = getRootDir();
179
- const lintRules = await collectLintRules(config, rootDir);
180
- await lint(undefined, {
181
- verbose: options.verbose,
182
- fix: options.fix,
183
- rules: lintRules,
184
- files: explicitFiles.length > 0 ? explicitFiles : undefined,
185
- });
186
- }
187
268
  }