ic-mops 2.14.0 → 2.14.1
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 +3 -0
- package/bundle/cli.tgz +0 -0
- package/commands/check.ts +22 -22
- package/dist/commands/check.js +20 -18
- package/dist/helpers/autofix-motoko.js +7 -8
- package/dist/package.json +1 -1
- package/dist/tests/check.test.js +6 -0
- package/helpers/autofix-motoko.ts +12 -13
- package/package.json +1 -1
- package/tests/__snapshots__/check.test.ts.snap +17 -4
- package/tests/check.test.ts +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## Next
|
|
4
4
|
|
|
5
|
+
## 2.14.1
|
|
6
|
+
- Speed up `mops check <files...>` (e.g. `mops check src/**/*.mo`) on packages with many files. Previously each file was checked in its own `moc` invocation, so every shared transitive import was re-parsed and re-type-checked once per file. All files are now passed to a single `moc --check` call, which loads and type-checks each import only once — on motoko-core (53 files) this drops a full check from ~27s to ~1.6s. The per-file `✓` confirmations now print only when the whole check passes.
|
|
7
|
+
|
|
5
8
|
## 2.14.0
|
|
6
9
|
- Fix `mops check --fix` crashing with `TypeError: Cannot read properties of undefined (reading 'split')` when `moc` produces no output (e.g. it fails to spawn or is killed by the OOM killer in a memory-constrained container). The autofix pass now treats missing `moc` output as "no fixes to apply" and lets the regular check report the real failure, instead of aborting the whole command with an unhandled exception.
|
|
7
10
|
|
package/bundle/cli.tgz
CHANGED
|
Binary file
|
package/commands/check.ts
CHANGED
|
@@ -262,30 +262,30 @@ async function checkFiles(
|
|
|
262
262
|
logAutofixResult(fixResult, options.verbose);
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const result = await execa(mocPath, args, {
|
|
274
|
-
stdio: "inherit",
|
|
275
|
-
reject: false,
|
|
276
|
-
});
|
|
265
|
+
// Check all files in a single moc invocation so shared transitive imports
|
|
266
|
+
// are chased and type-checked once, not re-checked for every file.
|
|
267
|
+
const args = [...files, ...mocArgs];
|
|
268
|
+
if (options.verbose) {
|
|
269
|
+
console.log(chalk.blue("check"), chalk.gray("Running moc:"));
|
|
270
|
+
console.log(chalk.gray(mocPath, JSON.stringify(args)));
|
|
271
|
+
}
|
|
277
272
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
273
|
+
try {
|
|
274
|
+
const result = await execa(mocPath, args, {
|
|
275
|
+
stdio: "inherit",
|
|
276
|
+
reject: false,
|
|
277
|
+
});
|
|
283
278
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
cliError(
|
|
287
|
-
`Error while checking ${file}${err?.message ? `\n${err.message}` : ""}`,
|
|
288
|
-
);
|
|
279
|
+
if (result.exitCode !== 0) {
|
|
280
|
+
cliError(`✗ Check failed (exit code: ${result.exitCode})`);
|
|
289
281
|
}
|
|
282
|
+
} catch (err: any) {
|
|
283
|
+
cliError(
|
|
284
|
+
`Error while checking files${err?.message ? `\n${err.message}` : ""}`,
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
for (const file of files) {
|
|
289
|
+
console.log(chalk.green(`✓ ${file}`));
|
|
290
290
|
}
|
|
291
291
|
}
|
package/dist/commands/check.js
CHANGED
|
@@ -171,24 +171,26 @@ async function checkFiles(config, files, options) {
|
|
|
171
171
|
const fixResult = await autofixMotoko(mocPath, files, mocArgs);
|
|
172
172
|
logAutofixResult(fixResult, options.verbose);
|
|
173
173
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
console.log(chalk.green(`✓ ${file}`));
|
|
189
|
-
}
|
|
190
|
-
catch (err) {
|
|
191
|
-
cliError(`Error while checking ${file}${err?.message ? `\n${err.message}` : ""}`);
|
|
174
|
+
// Check all files in a single moc invocation so shared transitive imports
|
|
175
|
+
// are chased and type-checked once, not re-checked for every file.
|
|
176
|
+
const args = [...files, ...mocArgs];
|
|
177
|
+
if (options.verbose) {
|
|
178
|
+
console.log(chalk.blue("check"), chalk.gray("Running moc:"));
|
|
179
|
+
console.log(chalk.gray(mocPath, JSON.stringify(args)));
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const result = await execa(mocPath, args, {
|
|
183
|
+
stdio: "inherit",
|
|
184
|
+
reject: false,
|
|
185
|
+
});
|
|
186
|
+
if (result.exitCode !== 0) {
|
|
187
|
+
cliError(`✗ Check failed (exit code: ${result.exitCode})`);
|
|
192
188
|
}
|
|
193
189
|
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
cliError(`Error while checking files${err?.message ? `\n${err.message}` : ""}`);
|
|
192
|
+
}
|
|
193
|
+
for (const file of files) {
|
|
194
|
+
console.log(chalk.green(`✓ ${file}`));
|
|
195
|
+
}
|
|
194
196
|
}
|
|
@@ -109,14 +109,13 @@ export async function autofixMotoko(mocPath, files, mocArgs) {
|
|
|
109
109
|
const fixedFilesCodes = new Map();
|
|
110
110
|
for (let iteration = 0; iteration < MAX_FIX_ITERATIONS; iteration++) {
|
|
111
111
|
const fixesByFile = new Map();
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
112
|
+
// Single invocation: moc dedups shared imports across all files.
|
|
113
|
+
const result = await execa(mocPath, [...files, ...mocArgs, "--error-format=json"], { stdio: "pipe", reject: false });
|
|
114
|
+
const diagnostics = parseDiagnostics(result.stdout);
|
|
115
|
+
for (const [targetFile, fixes] of extractDiagnosticFixes(diagnostics)) {
|
|
116
|
+
const existing = fixesByFile.get(targetFile) ?? [];
|
|
117
|
+
existing.push(...fixes);
|
|
118
|
+
fixesByFile.set(targetFile, existing);
|
|
120
119
|
}
|
|
121
120
|
if (fixesByFile.size === 0) {
|
|
122
121
|
break;
|
package/dist/package.json
CHANGED
package/dist/tests/check.test.js
CHANGED
|
@@ -12,6 +12,12 @@ describe("check", () => {
|
|
|
12
12
|
await cliSnapshot(["check", "Error.mo"], { cwd }, 1);
|
|
13
13
|
await cliSnapshot(["check", "Ok.mo", "Error.mo"], { cwd }, 1);
|
|
14
14
|
});
|
|
15
|
+
// The verbose snapshot shows a single "moc ... [both files]" line, proving the
|
|
16
|
+
// whole set is checked in one invocation rather than one moc call per file.
|
|
17
|
+
test("multiple files in a single invocation", async () => {
|
|
18
|
+
const cwd = path.join(import.meta.dirname, "check/success");
|
|
19
|
+
await cliSnapshot(["check", "Ok.mo", "Warning.mo", "--verbose"], { cwd }, 0);
|
|
20
|
+
});
|
|
15
21
|
test("warning", async () => {
|
|
16
22
|
const cwd = path.join(import.meta.dirname, "check/success");
|
|
17
23
|
const result = await cliSnapshot(["check", "Warning.mo"], { cwd }, 0);
|
|
@@ -184,19 +184,18 @@ export async function autofixMotoko(
|
|
|
184
184
|
for (let iteration = 0; iteration < MAX_FIX_ITERATIONS; iteration++) {
|
|
185
185
|
const fixesByFile = new Map<string, DiagnosticFix[]>();
|
|
186
186
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
187
|
+
// Single invocation: moc dedups shared imports across all files.
|
|
188
|
+
const result = await execa(
|
|
189
|
+
mocPath,
|
|
190
|
+
[...files, ...mocArgs, "--error-format=json"],
|
|
191
|
+
{ stdio: "pipe", reject: false },
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const diagnostics = parseDiagnostics(result.stdout);
|
|
195
|
+
for (const [targetFile, fixes] of extractDiagnosticFixes(diagnostics)) {
|
|
196
|
+
const existing = fixesByFile.get(targetFile) ?? [];
|
|
197
|
+
existing.push(...fixes);
|
|
198
|
+
fixesByFile.set(targetFile, existing);
|
|
200
199
|
}
|
|
201
200
|
|
|
202
201
|
if (fixesByFile.size === 0) {
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@ exports[`check [moc] args are passed to moc 1`] = `
|
|
|
5
5
|
"exitCode": 1,
|
|
6
6
|
"stderr": "Warning.mo:3.9-3.15: warning [M0194], unused identifier: \`unused\`
|
|
7
7
|
help: if this is intentional, prefix it with an underscore: \`_unused\`
|
|
8
|
-
✗ Check failed
|
|
8
|
+
✗ Check failed (exit code: 1)",
|
|
9
9
|
"stdout": "",
|
|
10
10
|
}
|
|
11
11
|
`;
|
|
@@ -18,7 +18,7 @@ exports[`check error 1`] = `
|
|
|
18
18
|
cannot produce expected type
|
|
19
19
|
()
|
|
20
20
|
Error.mo:7.1-7.21: type error [M0057], unbound variable thisshouldnotcompile
|
|
21
|
-
✗ Check failed
|
|
21
|
+
✗ Check failed (exit code: 1)",
|
|
22
22
|
"stdout": "",
|
|
23
23
|
}
|
|
24
24
|
`;
|
|
@@ -27,11 +27,24 @@ exports[`check error 2`] = `
|
|
|
27
27
|
{
|
|
28
28
|
"exitCode": 1,
|
|
29
29
|
"stderr": "Ok.mo: No such file or directory
|
|
30
|
-
✗ Check failed
|
|
30
|
+
✗ Check failed (exit code: 1)",
|
|
31
31
|
"stdout": "",
|
|
32
32
|
}
|
|
33
33
|
`;
|
|
34
34
|
|
|
35
|
+
exports[`check multiple files in a single invocation 1`] = `
|
|
36
|
+
{
|
|
37
|
+
"exitCode": 0,
|
|
38
|
+
"stderr": "Warning.mo:3.9-3.15: warning [M0194], unused identifier: \`unused\`
|
|
39
|
+
help: if this is intentional, prefix it with an underscore: \`_unused\`",
|
|
40
|
+
"stdout": "check Using --all-libs for richer diagnostics
|
|
41
|
+
check Running moc:
|
|
42
|
+
<CACHE>moc-wrapper ["Ok.mo","Warning.mo","--check","--all-libs","--default-persistent-actors"]
|
|
43
|
+
✓ Ok.mo
|
|
44
|
+
✓ Warning.mo",
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
|
|
35
48
|
exports[`check no args checks all canisters 1`] = `
|
|
36
49
|
{
|
|
37
50
|
"exitCode": 0,
|
|
@@ -85,7 +98,7 @@ exports[`check warning with -Werror flag 1`] = `
|
|
|
85
98
|
"exitCode": 1,
|
|
86
99
|
"stderr": "Warning.mo:3.9-3.15: warning [M0194], unused identifier: \`unused\`
|
|
87
100
|
help: if this is intentional, prefix it with an underscore: \`_unused\`
|
|
88
|
-
✗ Check failed
|
|
101
|
+
✗ Check failed (exit code: 1)",
|
|
89
102
|
"stdout": "",
|
|
90
103
|
}
|
|
91
104
|
`;
|
package/tests/check.test.ts
CHANGED
|
@@ -15,6 +15,17 @@ describe("check", () => {
|
|
|
15
15
|
await cliSnapshot(["check", "Ok.mo", "Error.mo"], { cwd }, 1);
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
+
// The verbose snapshot shows a single "moc ... [both files]" line, proving the
|
|
19
|
+
// whole set is checked in one invocation rather than one moc call per file.
|
|
20
|
+
test("multiple files in a single invocation", async () => {
|
|
21
|
+
const cwd = path.join(import.meta.dirname, "check/success");
|
|
22
|
+
await cliSnapshot(
|
|
23
|
+
["check", "Ok.mo", "Warning.mo", "--verbose"],
|
|
24
|
+
{ cwd },
|
|
25
|
+
0,
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
18
29
|
test("warning", async () => {
|
|
19
30
|
const cwd = path.join(import.meta.dirname, "check/success");
|
|
20
31
|
const result = await cliSnapshot(["check", "Warning.mo"], { cwd }, 0);
|