ic-mops 2.0.0 → 2.1.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 +13 -0
- package/RELEASE.md +179 -0
- package/bundle/cli.tgz +0 -0
- package/check-requirements.ts +3 -8
- package/cli.ts +79 -11
- package/commands/bench/bench-canister.mo +17 -6
- package/commands/bench.ts +2 -13
- package/commands/build.ts +42 -17
- package/commands/check.ts +117 -0
- package/commands/format.ts +3 -18
- package/commands/lint.ts +92 -0
- package/commands/sync.ts +2 -8
- package/commands/test/test.ts +7 -19
- package/commands/toolchain/index.ts +21 -8
- package/commands/toolchain/lintoko.ts +54 -0
- package/commands/toolchain/toolchain-utils.ts +2 -0
- package/constants.ts +23 -0
- package/dist/check-requirements.js +3 -8
- package/dist/cli.js +60 -10
- package/dist/commands/bench/bench-canister.mo +17 -6
- package/dist/commands/bench.js +2 -11
- package/dist/commands/build.js +38 -16
- package/dist/commands/check.d.ts +6 -0
- package/dist/commands/check.js +78 -0
- package/dist/commands/format.js +3 -16
- package/dist/commands/lint.d.ts +7 -0
- package/dist/commands/lint.js +69 -0
- package/dist/commands/sync.js +2 -7
- package/dist/commands/test/test.js +7 -17
- package/dist/commands/toolchain/index.d.ts +2 -2
- package/dist/commands/toolchain/index.js +18 -7
- package/dist/commands/toolchain/lintoko.d.ts +8 -0
- package/dist/commands/toolchain/lintoko.js +36 -0
- package/dist/commands/toolchain/toolchain-utils.d.ts +1 -0
- package/dist/commands/toolchain/toolchain-utils.js +1 -0
- package/dist/constants.d.ts +15 -0
- package/dist/constants.js +21 -0
- package/dist/environments/nodejs/cli.js +6 -1
- package/dist/helpers/autofix-motoko.d.ts +26 -0
- package/dist/helpers/autofix-motoko.js +105 -0
- package/dist/helpers/get-moc-version.d.ts +2 -0
- package/dist/helpers/get-moc-version.js +10 -1
- package/dist/mops.js +2 -1
- package/dist/package.json +4 -3
- package/dist/tests/build-no-dfx.test.d.ts +1 -0
- package/dist/tests/build-no-dfx.test.js +9 -0
- package/dist/tests/build.test.d.ts +1 -0
- package/dist/tests/build.test.js +18 -0
- package/dist/tests/check-candid.test.d.ts +1 -0
- package/dist/tests/check-candid.test.js +20 -0
- package/dist/tests/check-fix.test.d.ts +1 -0
- package/dist/tests/check-fix.test.js +73 -0
- package/dist/tests/check.test.d.ts +1 -0
- package/dist/tests/check.test.js +33 -0
- package/dist/tests/cli.test.js +4 -57
- package/dist/tests/helpers.d.ts +22 -0
- package/dist/tests/helpers.js +43 -0
- package/dist/tests/lint.test.d.ts +1 -0
- package/dist/tests/lint.test.js +15 -0
- package/dist/tests/toolchain.test.d.ts +1 -0
- package/dist/tests/toolchain.test.js +11 -0
- package/dist/types.d.ts +6 -1
- package/dist/wasm/pkg/nodejs/wasm.d.ts +3 -0
- package/dist/wasm/pkg/nodejs/wasm.js +323 -17
- package/dist/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
- package/dist/wasm/pkg/nodejs/wasm_bg.wasm.d.ts +6 -1
- package/dist/wasm/pkg/web/wasm.d.ts +10 -1
- package/dist/wasm/pkg/web/wasm.js +300 -21
- package/dist/wasm/pkg/web/wasm_bg.wasm +0 -0
- package/dist/wasm/pkg/web/wasm_bg.wasm.d.ts +6 -1
- package/dist/wasm.d.ts +6 -1
- package/environments/nodejs/cli.ts +7 -1
- package/helpers/autofix-motoko.ts +170 -0
- package/helpers/get-moc-version.ts +12 -1
- package/mops.ts +2 -1
- package/package.json +4 -3
- package/tests/__snapshots__/build-no-dfx.test.ts.snap +11 -0
- package/tests/__snapshots__/build.test.ts.snap +77 -0
- package/tests/__snapshots__/check-candid.test.ts.snap +73 -0
- package/tests/__snapshots__/check-fix.test.ts.snap +242 -0
- package/tests/__snapshots__/check.test.ts.snap +72 -0
- package/tests/__snapshots__/lint.test.ts.snap +78 -0
- package/tests/build/error/src/Bar.mo +2 -2
- package/tests/build/no-dfx/mops.toml +5 -0
- package/tests/build/no-dfx/src/Main.mo +5 -0
- package/tests/build/success/candid/bar.did +1 -0
- package/tests/build/success/mops.toml +8 -3
- package/tests/build-no-dfx.test.ts +10 -0
- package/tests/build.test.ts +24 -0
- package/tests/check/error/Error.mo +7 -0
- package/tests/check/error/mops.toml +2 -0
- package/tests/check/fix/M0223.mo +11 -0
- package/tests/check/fix/M0236.mo +11 -0
- package/tests/check/fix/M0237.mo +11 -0
- package/tests/check/fix/Ok.mo +7 -0
- package/tests/check/fix/edit-suggestions.mo +143 -0
- package/tests/check/fix/mops.toml +5 -0
- package/tests/check/fix/transitive-lib.mo +9 -0
- package/tests/check/fix/transitive-main.mo +9 -0
- package/tests/check/success/Ok.mo +5 -0
- package/tests/check/success/Warning.mo +5 -0
- package/tests/check/success/mops.toml +2 -0
- package/tests/check-candid.test.ts +22 -0
- package/tests/check-fix.test.ts +111 -0
- package/tests/check.test.ts +46 -0
- package/tests/cli.test.ts +4 -74
- package/tests/helpers.ts +58 -0
- package/tests/lint/lints/no-bool-switch.toml +9 -0
- package/tests/lint/mops.toml +4 -0
- package/tests/lint/src/NoBoolSwitch.mo +8 -0
- package/tests/lint/src/Ok.mo +5 -0
- package/tests/lint.test.ts +17 -0
- package/tests/toolchain/mock +2 -0
- package/tests/toolchain/mops.toml +2 -0
- package/tests/toolchain.test.ts +12 -0
- package/types.ts +6 -1
- package/wasm/Cargo.lock +101 -54
- package/wasm/Cargo.toml +2 -5
- package/wasm/pkg/nodejs/wasm.d.ts +3 -0
- package/wasm/pkg/nodejs/wasm.js +323 -17
- package/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
- package/wasm/pkg/nodejs/wasm_bg.wasm.d.ts +6 -1
- package/wasm/pkg/web/wasm.d.ts +10 -1
- package/wasm/pkg/web/wasm.js +300 -21
- package/wasm/pkg/web/wasm_bg.wasm +0 -0
- package/wasm/pkg/web/wasm_bg.wasm.d.ts +6 -1
- package/wasm/src/lib.rs +10 -5
- package/wasm/src/utils.rs +15 -0
- package/wasm/src/wasm_utils.rs +79 -0
- package/wasm.ts +10 -1
- package/.DS_Store +0 -0
- package/bundle/bench/bench-canister.mo +0 -121
- package/bundle/bench/user-bench.mo +0 -10
- package/bundle/bin/moc-wrapper.sh +0 -40
- package/bundle/bin/mops.js +0 -3
- package/bundle/cli.js +0 -2144
- package/bundle/declarations/bench/bench.did +0 -30
- package/bundle/declarations/bench/bench.did.d.ts +0 -33
- package/bundle/declarations/bench/bench.did.js +0 -30
- package/bundle/declarations/bench/index.d.ts +0 -50
- package/bundle/declarations/bench/index.js +0 -40
- package/bundle/declarations/main/index.d.ts +0 -50
- package/bundle/declarations/main/index.js +0 -40
- package/bundle/declarations/main/main.did +0 -428
- package/bundle/declarations/main/main.did.d.ts +0 -348
- package/bundle/declarations/main/main.did.js +0 -406
- package/bundle/declarations/storage/index.d.ts +0 -50
- package/bundle/declarations/storage/index.js +0 -30
- package/bundle/declarations/storage/storage.did +0 -46
- package/bundle/declarations/storage/storage.did.d.ts +0 -40
- package/bundle/declarations/storage/storage.did.js +0 -38
- package/bundle/package.json +0 -36
- package/bundle/templates/README.md +0 -13
- package/bundle/templates/licenses/Apache-2.0 +0 -202
- package/bundle/templates/licenses/Apache-2.0-NOTICE +0 -13
- package/bundle/templates/licenses/MIT +0 -21
- package/bundle/templates/mops-publish.yml +0 -17
- package/bundle/templates/mops-test.yml +0 -24
- package/bundle/templates/src/lib.mo +0 -15
- package/bundle/templates/test/lib.test.mo +0 -4
- package/bundle/wasm_bg.wasm +0 -0
- package/bundle/xhr-sync-worker.js +0 -59
- package/dist/wasm/pkg/bundler/package.json +0 -20
- package/dist/wasm/pkg/bundler/wasm.d.ts +0 -3
- package/dist/wasm/pkg/bundler/wasm.js +0 -5
- package/dist/wasm/pkg/bundler/wasm_bg.js +0 -93
- package/dist/wasm/pkg/bundler/wasm_bg.wasm +0 -0
- package/dist/wasm/pkg/bundler/wasm_bg.wasm.d.ts +0 -8
- package/tests/__snapshots__/cli.test.ts.snap +0 -202
- package/tests/build/success/.dfx/local/canister_ids.json +0 -17
- package/tests/build/success/.dfx/local/canisters/bar/bar.did +0 -3
- package/tests/build/success/.dfx/local/canisters/bar/bar.most +0 -4
- package/tests/build/success/.dfx/local/canisters/bar/bar.wasm +0 -0
- package/tests/build/success/.dfx/local/canisters/bar/constructor.did +0 -3
- package/tests/build/success/.dfx/local/canisters/bar/index.js +0 -42
- package/tests/build/success/.dfx/local/canisters/bar/init_args.txt +0 -1
- package/tests/build/success/.dfx/local/canisters/bar/service.did +0 -3
- package/tests/build/success/.dfx/local/canisters/bar/service.did.d.ts +0 -7
- package/tests/build/success/.dfx/local/canisters/bar/service.did.js +0 -4
- package/tests/build/success/.dfx/local/canisters/foo/constructor.did +0 -3
- package/tests/build/success/.dfx/local/canisters/foo/foo.did +0 -3
- package/tests/build/success/.dfx/local/canisters/foo/foo.most +0 -4
- package/tests/build/success/.dfx/local/canisters/foo/foo.wasm +0 -0
- package/tests/build/success/.dfx/local/canisters/foo/index.js +0 -42
- package/tests/build/success/.dfx/local/canisters/foo/init_args.txt +0 -1
- package/tests/build/success/.dfx/local/canisters/foo/service.did +0 -3
- package/tests/build/success/.dfx/local/canisters/foo/service.did.d.ts +0 -7
- package/tests/build/success/.dfx/local/canisters/foo/service.did.js +0 -4
- package/tests/build/success/.dfx/local/lsp/ucwa4-rx777-77774-qaada-cai.did +0 -3
- package/tests/build/success/.dfx/local/lsp/ulvla-h7777-77774-qaacq-cai.did +0 -3
- package/tests/build/success/.dfx/local/network-id +0 -4
- package/wasm/pkg/bundler/package.json +0 -20
- package/wasm/pkg/bundler/wasm.d.ts +0 -3
- package/wasm/pkg/bundler/wasm.js +0 -5
- package/wasm/pkg/bundler/wasm_bg.js +0 -93
- package/wasm/pkg/bundler/wasm_bg.wasm +0 -0
- package/wasm/pkg/bundler/wasm_bg.wasm.d.ts +0 -8
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import Map "mo:core/Map";
|
|
2
|
+
import Nat "mo:core/Nat";
|
|
3
|
+
import Text "mo:core/Text";
|
|
4
|
+
import { type Order } "mo:core/Order";
|
|
5
|
+
|
|
6
|
+
// --- M0223: redundant type instantiation ---
|
|
7
|
+
|
|
8
|
+
do {
|
|
9
|
+
func inferred<T>(x : T) : T = x;
|
|
10
|
+
let n1 = inferred<Nat>(1);
|
|
11
|
+
ignore n1;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// --- M0236: contextual dot notation ---
|
|
15
|
+
|
|
16
|
+
do {
|
|
17
|
+
let m = Map.empty<Nat, Text>();
|
|
18
|
+
// single arg
|
|
19
|
+
ignore Map.size(m); // warn M0236
|
|
20
|
+
|
|
21
|
+
// multi arg with implicit -> M0236 + M0237
|
|
22
|
+
ignore Map.get(m, Nat.compare, 1); // warn M0236 + M0237
|
|
23
|
+
|
|
24
|
+
// complex receiver
|
|
25
|
+
ignore Map.size(
|
|
26
|
+
Map.empty<Nat, Text>()
|
|
27
|
+
); // warn M0236
|
|
28
|
+
|
|
29
|
+
// multiline call -> M0236 + M0237
|
|
30
|
+
Map.add(
|
|
31
|
+
m,
|
|
32
|
+
Nat.compare,
|
|
33
|
+
1,
|
|
34
|
+
"John",
|
|
35
|
+
); // warn M0236 + M0237
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// --- M0237: implicit argument removal ---
|
|
39
|
+
|
|
40
|
+
do {
|
|
41
|
+
let m = Map.empty<Nat, Text>();
|
|
42
|
+
|
|
43
|
+
// single line
|
|
44
|
+
ignore m.get(Nat.compare, 1); // warn M0237
|
|
45
|
+
|
|
46
|
+
// multiline
|
|
47
|
+
ignore m.get(
|
|
48
|
+
Nat.compare,
|
|
49
|
+
1,
|
|
50
|
+
); // warn M0237
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// --- M0237: complex implicit patterns ---
|
|
54
|
+
|
|
55
|
+
module Impl {
|
|
56
|
+
// implicit in the middle: f(self, implicit, key)
|
|
57
|
+
public func get<K, V>(
|
|
58
|
+
self : [(K, V)],
|
|
59
|
+
_cmp : (implicit : (compare : (K, K) -> Order)),
|
|
60
|
+
key : K,
|
|
61
|
+
) : ?V { ignore self; ignore key; null };
|
|
62
|
+
|
|
63
|
+
// two adjacent implicits: f(self, implicit1, implicit2, key, value)
|
|
64
|
+
public func put<K, V>(
|
|
65
|
+
self : [(K, V)],
|
|
66
|
+
_cmpK : (implicit : (compare : (K, K) -> Order)),
|
|
67
|
+
_cmpV : (implicit : (compare : (V, V) -> Order)),
|
|
68
|
+
key : K,
|
|
69
|
+
value : V,
|
|
70
|
+
) : [(K, V)] { ignore key; ignore value; self };
|
|
71
|
+
|
|
72
|
+
// implicit at the end
|
|
73
|
+
public func find<K, V>(
|
|
74
|
+
self : [(K, V)],
|
|
75
|
+
key : K,
|
|
76
|
+
_cmp : (implicit : (compare : (K, K) -> Order)),
|
|
77
|
+
) : ?V { ignore self; ignore key; null };
|
|
78
|
+
public func sort1<K, V>(
|
|
79
|
+
self : [(K, V)],
|
|
80
|
+
_cmp : (implicit : (compare : (K, K) -> Order)),
|
|
81
|
+
) : [(K, V)] { self };
|
|
82
|
+
public func sort2<K, V>(
|
|
83
|
+
notSelf : [(K, V)],
|
|
84
|
+
_cmp : (implicit : (compare : (K, K) -> Order)),
|
|
85
|
+
) : [(K, V)] { notSelf };
|
|
86
|
+
|
|
87
|
+
// all implicits: f(implicit1, implicit2)
|
|
88
|
+
public func make<K, V>(
|
|
89
|
+
_cmpK : (implicit : (compare : (K, K) -> Order)),
|
|
90
|
+
_cmpV : (implicit : (compare : (V, V) -> Order)),
|
|
91
|
+
) : [(K, V)] { [] };
|
|
92
|
+
|
|
93
|
+
// non-adjacent implicits: f(self, implicit1, key, implicit2, value)
|
|
94
|
+
public func update<K, V>(
|
|
95
|
+
self : [(K, V)],
|
|
96
|
+
_cmpK : (implicit : (compare : (K, K) -> Order)),
|
|
97
|
+
key : K,
|
|
98
|
+
_cmpV : (implicit : (compare : (V, V) -> Order)),
|
|
99
|
+
value : V,
|
|
100
|
+
) : [(K, V)] { ignore key; ignore value; self };
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
do {
|
|
104
|
+
let data : [(Nat, Text)] = [];
|
|
105
|
+
|
|
106
|
+
// implicit in the middle -> M0236 + M0237
|
|
107
|
+
ignore Impl.get(data, Nat.compare, 1);
|
|
108
|
+
|
|
109
|
+
// two adjacent implicits -> M0236 + M0237 x2
|
|
110
|
+
ignore Impl.put(data, Nat.compare, Text.compare, 1, "a");
|
|
111
|
+
|
|
112
|
+
// implicit at the end -> M0236 + M0237
|
|
113
|
+
ignore Impl.find(data, 1, Nat.compare);
|
|
114
|
+
ignore Impl.sort1(data, Nat.compare); // -> M0236 + M0237
|
|
115
|
+
ignore Impl.sort2(data, Nat.compare); // no dot suggestion (notSelf), M0237 only
|
|
116
|
+
|
|
117
|
+
// all implicits -> M0237 x2
|
|
118
|
+
let _ = Impl.make<Nat, Text>(Nat.compare, Text.compare);
|
|
119
|
+
|
|
120
|
+
// non-adjacent implicits -> M0236 + M0237 x2
|
|
121
|
+
ignore Impl.update(data, Nat.compare, 1, Text.compare, "a");
|
|
122
|
+
|
|
123
|
+
// multiline: two adjacent implicits -> M0236 + M0237 x2
|
|
124
|
+
ignore Impl.put(
|
|
125
|
+
data,
|
|
126
|
+
Nat.compare,
|
|
127
|
+
Text.compare,
|
|
128
|
+
1,
|
|
129
|
+
"a",
|
|
130
|
+
);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// --- Mix: M0223 + M0236 + M0237 ---
|
|
134
|
+
|
|
135
|
+
do {
|
|
136
|
+
// NB: Must use `let _ = ...` to get the 'redundant type instantiation' error
|
|
137
|
+
let _ = Map.insert<Nat, Text>(
|
|
138
|
+
Map.empty<Nat, Text>(),
|
|
139
|
+
Nat.compare,
|
|
140
|
+
1,
|
|
141
|
+
"John",
|
|
142
|
+
); // warn M0223 + M0236 + M0237
|
|
143
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, test } from "@jest/globals";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { cliSnapshot } from "./helpers";
|
|
4
|
+
|
|
5
|
+
describe("check-candid", () => {
|
|
6
|
+
test("ok", async () => {
|
|
7
|
+
const cwd = path.join(import.meta.dirname, "check-candid");
|
|
8
|
+
await cliSnapshot(["check-candid", "a.did", "a.did"], { cwd }, 0);
|
|
9
|
+
await cliSnapshot(["check-candid", "b.did", "b.did"], { cwd }, 0);
|
|
10
|
+
await cliSnapshot(["check-candid", "c.did", "c.did"], { cwd }, 0);
|
|
11
|
+
await cliSnapshot(["check-candid", "a.did", "b.did"], { cwd }, 0);
|
|
12
|
+
await cliSnapshot(["check-candid", "b.did", "a.did"], { cwd }, 0);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("error", async () => {
|
|
16
|
+
const cwd = path.join(import.meta.dirname, "check-candid");
|
|
17
|
+
await cliSnapshot(["check-candid", "a.did", "c.did"], { cwd }, 1);
|
|
18
|
+
await cliSnapshot(["check-candid", "c.did", "a.did"], { cwd }, 1);
|
|
19
|
+
await cliSnapshot(["check-candid", "b.did", "c.did"], { cwd }, 1);
|
|
20
|
+
await cliSnapshot(["check-candid", "c.did", "b.did"], { cwd }, 1);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, test } from "@jest/globals";
|
|
2
|
+
import { cpSync, readdirSync, readFileSync, unlinkSync } from "node:fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { parseDiagnostics } from "../helpers/autofix-motoko";
|
|
5
|
+
import { cli, normalizePaths } from "./helpers";
|
|
6
|
+
|
|
7
|
+
function countCodes(stdout: string): Record<string, number> {
|
|
8
|
+
const counts: Record<string, number> = {};
|
|
9
|
+
for (const diag of parseDiagnostics(stdout)) {
|
|
10
|
+
counts[diag.code] = (counts[diag.code] ?? 0) + 1;
|
|
11
|
+
}
|
|
12
|
+
return counts;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe("check --fix", () => {
|
|
16
|
+
const fixDir = path.join(import.meta.dirname, "check/fix");
|
|
17
|
+
const runDir = path.join(fixDir, "run");
|
|
18
|
+
const warningFlags = "-W=M0223,M0236,M0237";
|
|
19
|
+
const diagnosticFlags = [warningFlags, "--error-format=json"];
|
|
20
|
+
|
|
21
|
+
beforeAll(() => {
|
|
22
|
+
for (const file of readdirSync(runDir).filter((f) => f.endsWith(".mo"))) {
|
|
23
|
+
unlinkSync(path.join(runDir, file));
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
function copyFixture(file: string): string {
|
|
28
|
+
const dest = path.join(runDir, file);
|
|
29
|
+
cpSync(path.join(fixDir, file), dest);
|
|
30
|
+
return dest;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function testCheckFix(
|
|
34
|
+
file: string,
|
|
35
|
+
expectedDiagnostics: Record<string, number>,
|
|
36
|
+
expectedAfterDiagnostics: Record<string, number> = {},
|
|
37
|
+
): Promise<string> {
|
|
38
|
+
const runFilePath = copyFixture(file);
|
|
39
|
+
|
|
40
|
+
const beforeResult = await cli(
|
|
41
|
+
["check", runFilePath, "--", ...diagnosticFlags],
|
|
42
|
+
{ cwd: fixDir },
|
|
43
|
+
);
|
|
44
|
+
expect(countCodes(beforeResult.stdout)).toEqual(expectedDiagnostics);
|
|
45
|
+
|
|
46
|
+
const fixResult = await cli(
|
|
47
|
+
["check", runFilePath, "--fix", "--", warningFlags],
|
|
48
|
+
{ cwd: fixDir },
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
expect(normalizePaths(fixResult.stdout)).toMatchSnapshot("fix output");
|
|
52
|
+
expect(readFileSync(runFilePath, "utf-8")).toMatchSnapshot();
|
|
53
|
+
|
|
54
|
+
const afterResult = await cli(
|
|
55
|
+
["check", runFilePath, "--", ...diagnosticFlags],
|
|
56
|
+
{ cwd: fixDir },
|
|
57
|
+
);
|
|
58
|
+
expect(countCodes(afterResult.stdout)).toEqual(expectedAfterDiagnostics);
|
|
59
|
+
|
|
60
|
+
return runFilePath;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
test("M0223", async () => {
|
|
64
|
+
await testCheckFix("M0223.mo", { M0223: 1 });
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("M0236", async () => {
|
|
68
|
+
await testCheckFix("M0236.mo", { M0236: 1 });
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("M0237", async () => {
|
|
72
|
+
await testCheckFix("M0237.mo", { M0237: 1 });
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("edit-suggestions", async () => {
|
|
76
|
+
await testCheckFix("edit-suggestions.mo", {
|
|
77
|
+
M0223: 2,
|
|
78
|
+
M0236: 11,
|
|
79
|
+
M0237: 17,
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("transitive imports", async () => {
|
|
84
|
+
const runMainPath = copyFixture("transitive-main.mo");
|
|
85
|
+
const runLibPath = copyFixture("transitive-lib.mo");
|
|
86
|
+
|
|
87
|
+
const fixResult = await cli(
|
|
88
|
+
["check", runMainPath, "--fix", "--", warningFlags],
|
|
89
|
+
{ cwd: fixDir },
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
expect(normalizePaths(fixResult.stdout)).toMatchSnapshot("fix output");
|
|
93
|
+
expect(readFileSync(runMainPath, "utf-8")).toMatchSnapshot("main file");
|
|
94
|
+
expect(readFileSync(runLibPath, "utf-8")).toMatchSnapshot("lib file");
|
|
95
|
+
|
|
96
|
+
const afterResult = await cli(
|
|
97
|
+
["check", runMainPath, "--", ...diagnosticFlags],
|
|
98
|
+
{ cwd: fixDir },
|
|
99
|
+
);
|
|
100
|
+
expect(countCodes(afterResult.stdout)).toEqual({});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("verbose", async () => {
|
|
104
|
+
const result = await cli(["check", "Ok.mo", "--fix", "--verbose"], {
|
|
105
|
+
cwd: fixDir,
|
|
106
|
+
});
|
|
107
|
+
expect(result.exitCode).toBe(0);
|
|
108
|
+
expect(result.stdout).toContain("Attempting to fix files");
|
|
109
|
+
expect(result.stdout).toContain("No fixes were needed");
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { cliSnapshot } from "./helpers";
|
|
4
|
+
|
|
5
|
+
describe("check", () => {
|
|
6
|
+
test("ok", async () => {
|
|
7
|
+
const cwd = path.join(import.meta.dirname, "check/success");
|
|
8
|
+
await cliSnapshot(["check", "Ok.mo"], { cwd }, 0);
|
|
9
|
+
await cliSnapshot(["check", "Ok.mo", "--verbose"], { cwd }, 0);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("error", async () => {
|
|
13
|
+
const cwd = path.join(import.meta.dirname, "check/error");
|
|
14
|
+
await cliSnapshot(["check", "Error.mo"], { cwd }, 1);
|
|
15
|
+
await cliSnapshot(["check", "Ok.mo", "Error.mo"], { cwd }, 1);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("warning", async () => {
|
|
19
|
+
const cwd = path.join(import.meta.dirname, "check/success");
|
|
20
|
+
const result = await cliSnapshot(["check", "Warning.mo"], { cwd }, 0);
|
|
21
|
+
expect(result.stderr).toMatch(/warning \[M0194\]/);
|
|
22
|
+
expect(result.stderr).toMatch(/unused identifier/);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("warning verbose", async () => {
|
|
26
|
+
const cwd = path.join(import.meta.dirname, "check/success");
|
|
27
|
+
const result = await cliSnapshot(
|
|
28
|
+
["check", "Warning.mo", "--verbose"],
|
|
29
|
+
{ cwd },
|
|
30
|
+
0,
|
|
31
|
+
);
|
|
32
|
+
expect(result.stderr).toMatch(/warning \[M0194\]/);
|
|
33
|
+
expect(result.stderr).toMatch(/unused identifier/);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("warning with -Werror flag", async () => {
|
|
37
|
+
const cwd = path.join(import.meta.dirname, "check/success");
|
|
38
|
+
const result = await cliSnapshot(
|
|
39
|
+
["check", "Warning.mo", "--", "-Werror"],
|
|
40
|
+
{ cwd },
|
|
41
|
+
1,
|
|
42
|
+
);
|
|
43
|
+
expect(result.stderr).toMatch(/warning \[M0194\]/);
|
|
44
|
+
expect(result.stderr).toMatch(/unused identifier/);
|
|
45
|
+
});
|
|
46
|
+
});
|
package/tests/cli.test.ts
CHANGED
|
@@ -1,82 +1,12 @@
|
|
|
1
1
|
import { describe, expect, test } from "@jest/globals";
|
|
2
|
-
import {
|
|
3
|
-
import path from "path";
|
|
2
|
+
import { cli } from "./helpers";
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const cli = async (args: string[], { cwd }: CliOptions = {}) => {
|
|
10
|
-
return await execa("npm", ["run", "mops", "--", ...args], {
|
|
11
|
-
env: { MOPS_CWD: cwd },
|
|
12
|
-
stdio: "pipe",
|
|
13
|
-
reject: false,
|
|
14
|
-
});
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const cliSnapshot = async (
|
|
18
|
-
args: string[],
|
|
19
|
-
options: CliOptions,
|
|
20
|
-
exitCode: number,
|
|
21
|
-
) => {
|
|
22
|
-
const result = await cli(args, options);
|
|
23
|
-
expect({
|
|
24
|
-
command: result.command,
|
|
25
|
-
exitCode: result.exitCode,
|
|
26
|
-
timedOut: result.timedOut,
|
|
27
|
-
stdio: Boolean(result.stdout || result.stderr),
|
|
28
|
-
}).toEqual({
|
|
29
|
-
command: result.command,
|
|
30
|
-
exitCode,
|
|
31
|
-
timedOut: false,
|
|
32
|
-
stdio: true,
|
|
33
|
-
});
|
|
34
|
-
expect({
|
|
35
|
-
exitCode: result.exitCode,
|
|
36
|
-
stdout: result.stdout,
|
|
37
|
-
stderr: result.stderr,
|
|
38
|
-
}).toMatchSnapshot();
|
|
39
|
-
return result;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
describe("mops", () => {
|
|
43
|
-
test("version", async () => {
|
|
4
|
+
describe("cli", () => {
|
|
5
|
+
test("--version", async () => {
|
|
44
6
|
expect((await cli(["--version"])).stdout).toMatch(/CLI \d+\.\d+\.\d+/);
|
|
45
7
|
});
|
|
46
8
|
|
|
47
|
-
test("help", async () => {
|
|
9
|
+
test("--help", async () => {
|
|
48
10
|
expect((await cli(["--help"])).stdout).toMatch(/^Usage: mops/m);
|
|
49
11
|
});
|
|
50
|
-
|
|
51
|
-
test("build success", async () => {
|
|
52
|
-
const cwd = path.join(import.meta.dirname, "build/success");
|
|
53
|
-
await cliSnapshot(["build"], { cwd }, 0);
|
|
54
|
-
await cliSnapshot(["build", "foo"], { cwd }, 0);
|
|
55
|
-
await cliSnapshot(["build", "bar"], { cwd }, 0);
|
|
56
|
-
await cliSnapshot(["build", "foo", "bar"], { cwd }, 0);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test("build error", async () => {
|
|
60
|
-
const cwd = path.join(import.meta.dirname, "build/error");
|
|
61
|
-
await cliSnapshot(["build", "foo"], { cwd }, 0);
|
|
62
|
-
expect((await cliSnapshot(["build", "bar"], { cwd }, 1)).stderr).toMatch(
|
|
63
|
-
"Candid compatibility check failed for canister bar",
|
|
64
|
-
);
|
|
65
|
-
expect(
|
|
66
|
-
(await cliSnapshot(["build", "foo", "bar"], { cwd }, 1)).stderr,
|
|
67
|
-
).toMatch("Candid compatibility check failed for canister bar");
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test("check-candid", async () => {
|
|
71
|
-
const cwd = path.join(import.meta.dirname, "check-candid");
|
|
72
|
-
await cliSnapshot(["check-candid", "a.did", "a.did"], { cwd }, 0);
|
|
73
|
-
await cliSnapshot(["check-candid", "b.did", "b.did"], { cwd }, 0);
|
|
74
|
-
await cliSnapshot(["check-candid", "c.did", "c.did"], { cwd }, 0);
|
|
75
|
-
await cliSnapshot(["check-candid", "a.did", "b.did"], { cwd }, 0);
|
|
76
|
-
await cliSnapshot(["check-candid", "b.did", "a.did"], { cwd }, 0);
|
|
77
|
-
await cliSnapshot(["check-candid", "a.did", "c.did"], { cwd }, 1);
|
|
78
|
-
await cliSnapshot(["check-candid", "c.did", "a.did"], { cwd }, 1);
|
|
79
|
-
await cliSnapshot(["check-candid", "b.did", "c.did"], { cwd }, 1);
|
|
80
|
-
await cliSnapshot(["check-candid", "c.did", "b.did"], { cwd }, 1);
|
|
81
|
-
});
|
|
82
12
|
});
|
package/tests/helpers.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { expect } from "@jest/globals";
|
|
2
|
+
import { execa } from "execa";
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
|
|
6
|
+
export interface CliOptions {
|
|
7
|
+
cwd?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const cli = async (args: string[], { cwd }: CliOptions = {}) => {
|
|
11
|
+
return await execa("npm", ["run", "--silent", "mops", "--", ...args], {
|
|
12
|
+
env: { ...process.env, ...(cwd != null && { MOPS_CWD: cwd }) },
|
|
13
|
+
...(cwd != null && { cwd }),
|
|
14
|
+
stdio: "pipe",
|
|
15
|
+
reject: false,
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Strip ANSI escape codes for portable snapshots (avoid control char in regex literal)
|
|
20
|
+
const stripAnsi = (s: string) =>
|
|
21
|
+
s.replace(new RegExp(`\u001b\\[[0-9;]*m`, "g"), "");
|
|
22
|
+
|
|
23
|
+
export const normalizePaths = (text: string): string => {
|
|
24
|
+
// Replace absolute paths with placeholders for CI
|
|
25
|
+
return stripAnsi(
|
|
26
|
+
text
|
|
27
|
+
.replaceAll(dirname(fileURLToPath(import.meta.url)), "<TEST_DIR>")
|
|
28
|
+
.replace(/\/[^\s"]+\/\.cache\/mops/g, "<CACHE>")
|
|
29
|
+
.replace(/\/[^\s"]+\/Library\/Caches\/mops/g, "<CACHE>")
|
|
30
|
+
.replace(/\/[^\s"[\]]+\/moc(?:-wrapper)?(?=\s|$)/g, "moc-wrapper")
|
|
31
|
+
.replace(/\/[^\s"[\]]+\.motoko\/bin\/moc/g, "moc-wrapper"),
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const cliSnapshot = async (
|
|
36
|
+
args: string[],
|
|
37
|
+
options: CliOptions,
|
|
38
|
+
exitCode: number,
|
|
39
|
+
) => {
|
|
40
|
+
const result = await cli(args, options);
|
|
41
|
+
expect({
|
|
42
|
+
command: result.command,
|
|
43
|
+
exitCode: result.exitCode,
|
|
44
|
+
timedOut: result.timedOut,
|
|
45
|
+
stdio: Boolean(result.stdout || result.stderr),
|
|
46
|
+
}).toEqual({
|
|
47
|
+
command: result.command,
|
|
48
|
+
exitCode,
|
|
49
|
+
timedOut: false,
|
|
50
|
+
stdio: true,
|
|
51
|
+
});
|
|
52
|
+
expect({
|
|
53
|
+
exitCode: result.exitCode,
|
|
54
|
+
stdout: normalizePaths(result.stdout),
|
|
55
|
+
stderr: normalizePaths(result.stderr),
|
|
56
|
+
}).toMatchSnapshot();
|
|
57
|
+
return result;
|
|
58
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { describe, test } from "@jest/globals";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { cliSnapshot } from "./helpers";
|
|
4
|
+
|
|
5
|
+
describe("lint", () => {
|
|
6
|
+
test("ok", async () => {
|
|
7
|
+
const cwd = path.join(import.meta.dirname, "lint");
|
|
8
|
+
await cliSnapshot(["lint", "Ok", "--verbose"], { cwd }, 0);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("error", async () => {
|
|
12
|
+
const cwd = path.join(import.meta.dirname, "lint");
|
|
13
|
+
await cliSnapshot(["lint", "--verbose"], { cwd }, 1);
|
|
14
|
+
await cliSnapshot(["lint", "NoBoolSwitch", "--verbose"], { cwd }, 1);
|
|
15
|
+
await cliSnapshot(["lint", "DoesNotExist"], { cwd }, 1);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { cli } from "./helpers";
|
|
4
|
+
|
|
5
|
+
describe("toolchain", () => {
|
|
6
|
+
test("file URI", async () => {
|
|
7
|
+
const cwd = path.join(import.meta.dirname, "toolchain");
|
|
8
|
+
const result = await cli(["toolchain", "bin", "moc"], { cwd });
|
|
9
|
+
expect(result.exitCode).toBe(0);
|
|
10
|
+
expect(result.stdout.trim()).toBe("./mock");
|
|
11
|
+
});
|
|
12
|
+
});
|
package/types.ts
CHANGED
|
@@ -24,12 +24,16 @@ export type Config = {
|
|
|
24
24
|
outputDir?: string;
|
|
25
25
|
args?: string[];
|
|
26
26
|
};
|
|
27
|
+
lint?: {
|
|
28
|
+
args?: string[];
|
|
29
|
+
};
|
|
27
30
|
};
|
|
28
31
|
|
|
29
32
|
export type CanisterConfig = {
|
|
30
33
|
main: string;
|
|
31
34
|
args?: string[];
|
|
32
35
|
candid?: string;
|
|
36
|
+
initArg?: string;
|
|
33
37
|
};
|
|
34
38
|
|
|
35
39
|
export type Dependencies = Record<string, Dependency>;
|
|
@@ -45,9 +49,10 @@ export type Toolchain = {
|
|
|
45
49
|
moc?: string;
|
|
46
50
|
wasmtime?: string;
|
|
47
51
|
"pocket-ic"?: string;
|
|
52
|
+
lintoko?: string;
|
|
48
53
|
};
|
|
49
54
|
|
|
50
|
-
export type Tool = "moc" | "wasmtime" | "pocket-ic";
|
|
55
|
+
export type Tool = "moc" | "wasmtime" | "pocket-ic" | "lintoko";
|
|
51
56
|
|
|
52
57
|
export type Requirements = {
|
|
53
58
|
moc?: string;
|