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 +6 -0
- package/bundle/cli.tgz +0 -0
- package/cli.ts +10 -10
- package/commands/build.ts +7 -22
- package/commands/check-stable.ts +110 -17
- package/commands/check.ts +183 -102
- package/dist/cli.js +10 -10
- package/dist/commands/build.js +3 -13
- package/dist/commands/check-stable.d.ts +7 -1
- package/dist/commands/check-stable.js +83 -19
- package/dist/commands/check.d.ts +1 -1
- package/dist/commands/check.js +127 -78
- package/dist/helpers/resolve-canisters.d.ts +3 -1
- package/dist/helpers/resolve-canisters.js +20 -5
- package/dist/package.json +1 -1
- package/dist/tests/check-stable.test.js +18 -0
- package/dist/tests/check.test.js +23 -5
- package/helpers/resolve-canisters.ts +36 -5
- package/package.json +1 -1
- package/tests/__snapshots__/check.test.ts.snap +2 -2
- package/tests/check/canisters-canister-args/Warning.mo +5 -0
- package/tests/check/canisters-canister-args/mops.toml +9 -0
- package/tests/check-stable/canister-args/migrations/20250101_000000_Init.mo +8 -0
- package/tests/check-stable/canister-args/migrations/20250201_000000_AddField.mo +9 -0
- package/tests/check-stable/canister-args/mops.toml +9 -0
- package/tests/check-stable/canister-args/old.most +8 -0
- package/tests/check-stable/canister-args/src/main.mo +11 -0
- package/tests/check-stable.test.ts +21 -0
- package/tests/check.test.ts +26 -5
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 [
|
|
333
|
+
.command("check [args...]")
|
|
334
334
|
.description(
|
|
335
|
-
"Check Motoko files for syntax errors and type issues. If no
|
|
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 (
|
|
345
|
+
.action(async (args, options) => {
|
|
346
346
|
checkConfigFile(true);
|
|
347
|
-
const { extraArgs, args:
|
|
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(
|
|
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
|
|
375
|
+
.command("check-stable [args...]")
|
|
376
376
|
.description(
|
|
377
|
-
"Check stable variable compatibility
|
|
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 (
|
|
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(
|
|
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 {
|
|
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
|
-
|
|
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) {
|
package/commands/check-stable.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
21
|
-
canisterName: string | undefined,
|
|
56
|
+
args: string[],
|
|
22
57
|
options: Partial<CheckStableOptions> = {},
|
|
23
58
|
): Promise<void> {
|
|
24
59
|
const config = readConfig();
|
|
25
|
-
const
|
|
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
|
-
|
|
28
|
-
|
|
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
|
|
32
|
-
const
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
17
|
+
validateCanisterArgs,
|
|
17
18
|
} from "../helpers/resolve-canisters.js";
|
|
18
|
-
import {
|
|
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
|
-
|
|
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 (
|
|
46
|
-
fileList = resolveCanisterEntrypoints(config).map(resolveConfigPath);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (fileList.length === 0) {
|
|
92
|
+
if (isFileMode && nonFileArgs.length > 0) {
|
|
50
93
|
cliError(
|
|
51
|
-
|
|
52
|
-
"
|
|
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
|
-
|
|
63
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
|
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,
|
|
92
|
-
|
|
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
|
|
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
|
}
|