ic-mops 2.0.1 → 2.2.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 +18 -0
- package/RELEASE.md +198 -0
- package/bundle/cli.tgz +0 -0
- package/check-requirements.ts +3 -8
- package/cli.ts +94 -11
- package/commands/bench/bench-canister.mo +17 -6
- package/commands/bench.ts +13 -16
- package/commands/build.ts +5 -6
- package/commands/check.ts +121 -0
- package/commands/format.ts +3 -18
- package/commands/lint.ts +92 -0
- package/commands/sync.ts +2 -8
- package/commands/test/test.ts +10 -20
- package/commands/toolchain/index.ts +21 -8
- package/commands/toolchain/lintoko.ts +54 -0
- package/commands/toolchain/toolchain-utils.ts +2 -0
- package/commands/watch/error-checker.ts +8 -2
- package/commands/watch/warning-checker.ts +8 -2
- package/constants.ts +23 -0
- package/dist/check-requirements.js +3 -8
- package/dist/cli.js +73 -11
- package/dist/commands/bench/bench-canister.mo +17 -6
- package/dist/commands/bench.js +7 -15
- package/dist/commands/build.js +5 -6
- package/dist/commands/check.d.ts +6 -0
- package/dist/commands/check.js +82 -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 +10 -18
- 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/commands/watch/error-checker.js +8 -2
- package/dist/commands/watch/warning-checker.js +8 -2
- package/dist/constants.d.ts +15 -0
- package/dist/constants.js +21 -0
- package/dist/environments/nodejs/cli.js +6 -1
- package/dist/error.d.ts +1 -1
- package/dist/helpers/autofix-motoko.d.ts +26 -0
- package/dist/helpers/autofix-motoko.js +150 -0
- package/dist/helpers/get-moc-version.d.ts +2 -0
- package/dist/helpers/get-moc-version.js +10 -1
- package/dist/mops.d.ts +1 -0
- package/dist/mops.js +12 -1
- package/dist/package.json +3 -2
- 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 +89 -0
- package/dist/tests/check.test.d.ts +1 -0
- package/dist/tests/check.test.js +37 -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/moc-args.test.d.ts +1 -0
- package/dist/tests/moc-args.test.js +17 -0
- package/dist/tests/toolchain.test.d.ts +1 -0
- package/dist/tests/toolchain.test.js +11 -0
- package/dist/types.d.ts +8 -1
- package/dist/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
- package/dist/wasm/pkg/web/wasm_bg.wasm +0 -0
- package/environments/nodejs/cli.ts +7 -1
- package/error.ts +1 -1
- package/helpers/autofix-motoko.ts +240 -0
- package/helpers/get-moc-version.ts +12 -1
- package/mops.ts +15 -1
- package/package.json +3 -2
- 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 +261 -0
- package/tests/__snapshots__/check.test.ts.snap +81 -0
- package/tests/__snapshots__/lint.test.ts.snap +78 -0
- package/tests/build/no-dfx/mops.toml +5 -0
- package/tests/build/no-dfx/src/Main.mo +5 -0
- 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/overlapping.mo +10 -0
- package/tests/check/fix/transitive-lib.mo +9 -0
- package/tests/check/fix/transitive-main.mo +9 -0
- package/tests/check/moc-args/Warning.mo +5 -0
- package/tests/check/moc-args/mops.toml +2 -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 +134 -0
- package/tests/check.test.ts +51 -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/moc-args.test.ts +19 -0
- package/tests/toolchain/mock +2 -0
- package/tests/toolchain/mops.toml +2 -0
- package/tests/toolchain.test.ts +12 -0
- package/types.ts +8 -1
- package/wasm/Cargo.lock +101 -54
- package/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
- package/wasm/pkg/web/wasm_bg.wasm +0 -0
- 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
|
@@ -11,6 +11,8 @@ import { checkRequirements } from "../../check-requirements.js";
|
|
|
11
11
|
import * as moc from "./moc.js";
|
|
12
12
|
import * as pocketIc from "./pocket-ic.js";
|
|
13
13
|
import * as wasmtime from "./wasmtime.js";
|
|
14
|
+
import * as lintoko from "./lintoko.js";
|
|
15
|
+
import { FILE_PATH_REGEX } from "../../constants.js";
|
|
14
16
|
function getToolUtils(tool) {
|
|
15
17
|
if (tool === "moc") {
|
|
16
18
|
return moc;
|
|
@@ -21,12 +23,15 @@ function getToolUtils(tool) {
|
|
|
21
23
|
else if (tool === "wasmtime") {
|
|
22
24
|
return wasmtime;
|
|
23
25
|
}
|
|
26
|
+
else if (tool === "lintoko") {
|
|
27
|
+
return lintoko;
|
|
28
|
+
}
|
|
24
29
|
else {
|
|
25
30
|
console.error(`Unknown tool '${tool}'`);
|
|
26
31
|
process.exit(1);
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
|
-
async function
|
|
34
|
+
async function checkToolchainInited({ strict = false } = {}) {
|
|
30
35
|
// auto init in CI
|
|
31
36
|
if (process.env.CI) {
|
|
32
37
|
await init({ silent: true });
|
|
@@ -47,8 +52,8 @@ async function ensureToolchainInited({ strict = true } = {}) {
|
|
|
47
52
|
}
|
|
48
53
|
}
|
|
49
54
|
catch { }
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
process.stderr.write(`${chalk.yellow('Toolchain management is not initialized. Run "mops toolchain init" to use with dfx.')}\n`);
|
|
56
|
+
return false;
|
|
52
57
|
}
|
|
53
58
|
// update shell config files to set DFX_MOC_PATH to moc-wrapper
|
|
54
59
|
async function init({ reset = false, silent = false } = {}) {
|
|
@@ -172,6 +177,9 @@ async function installAll({ silent = false, verbose = false } = {}) {
|
|
|
172
177
|
verbose,
|
|
173
178
|
});
|
|
174
179
|
}
|
|
180
|
+
if (config.toolchain?.lintoko) {
|
|
181
|
+
await download("lintoko", config.toolchain.lintoko, { silent, verbose });
|
|
182
|
+
}
|
|
175
183
|
if (!silent) {
|
|
176
184
|
logUpdate.clear();
|
|
177
185
|
console.log(chalk.green("Toolchain installed"));
|
|
@@ -204,7 +212,7 @@ async function promptVersion(tool) {
|
|
|
204
212
|
// download binary and set version in mops.toml
|
|
205
213
|
async function use(tool, version) {
|
|
206
214
|
if (tool === "moc") {
|
|
207
|
-
await
|
|
215
|
+
await checkToolchainInited();
|
|
208
216
|
}
|
|
209
217
|
if (!version) {
|
|
210
218
|
version = await promptVersion(tool);
|
|
@@ -232,7 +240,7 @@ async function use(tool, version) {
|
|
|
232
240
|
// download latest binary and set version in mops.toml
|
|
233
241
|
async function update(tool) {
|
|
234
242
|
if (tool === "moc") {
|
|
235
|
-
await
|
|
243
|
+
await checkToolchainInited();
|
|
236
244
|
}
|
|
237
245
|
let config = readConfig();
|
|
238
246
|
config.toolchain = config.toolchain || {};
|
|
@@ -273,8 +281,11 @@ async function bin(tool, { fallback = false } = {}) {
|
|
|
273
281
|
let config = readConfig();
|
|
274
282
|
let version = config.toolchain?.[tool];
|
|
275
283
|
if (version) {
|
|
284
|
+
if (version.match(FILE_PATH_REGEX)) {
|
|
285
|
+
return version;
|
|
286
|
+
}
|
|
276
287
|
if (tool === "moc") {
|
|
277
|
-
await
|
|
288
|
+
await checkToolchainInited();
|
|
278
289
|
}
|
|
279
290
|
await download(tool, version, { silent: true });
|
|
280
291
|
if (tool === "moc") {
|
|
@@ -300,5 +311,5 @@ export let toolchain = {
|
|
|
300
311
|
update,
|
|
301
312
|
bin,
|
|
302
313
|
installAll,
|
|
303
|
-
|
|
314
|
+
checkToolchainInited,
|
|
304
315
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare let repo: string;
|
|
2
|
+
export declare let getLatestReleaseTag: () => Promise<string>;
|
|
3
|
+
export declare let getReleases: () => Promise<any>;
|
|
4
|
+
export declare let isCached: (version: string) => boolean;
|
|
5
|
+
export declare let download: (version: string, { silent, verbose }?: {
|
|
6
|
+
silent?: boolean | undefined;
|
|
7
|
+
verbose?: boolean | undefined;
|
|
8
|
+
}) => Promise<void>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { globalCacheDir } from "../../mops.js";
|
|
5
|
+
import * as toolchainUtils from "./toolchain-utils.js";
|
|
6
|
+
let cacheDir = path.join(globalCacheDir, "lintoko");
|
|
7
|
+
export let repo = "caffeinelabs/lintoko";
|
|
8
|
+
export let getLatestReleaseTag = async () => {
|
|
9
|
+
return toolchainUtils.getLatestReleaseTag(repo);
|
|
10
|
+
};
|
|
11
|
+
export let getReleases = async () => {
|
|
12
|
+
return toolchainUtils.getReleases(repo);
|
|
13
|
+
};
|
|
14
|
+
export let isCached = (version) => {
|
|
15
|
+
let dir = path.join(cacheDir, version);
|
|
16
|
+
return fs.existsSync(dir) && fs.existsSync(path.join(dir, "lintoko"));
|
|
17
|
+
};
|
|
18
|
+
export let download = async (version, { silent = false, verbose = false } = {}) => {
|
|
19
|
+
if (!version) {
|
|
20
|
+
console.error("version is not defined");
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
if (isCached(version)) {
|
|
24
|
+
if (verbose) {
|
|
25
|
+
console.log(`lintoko ${version} is already installed`);
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
let platform = process.platform == "darwin" ? "apple-darwin" : "unknown-linux-gnu";
|
|
30
|
+
let arch = process.arch.startsWith("arm") ? "aarch64" : "x86_64";
|
|
31
|
+
let url = `https://github.com/caffeinelabs/lintoko/releases/download/v${version}/lintoko-${arch}-${platform}.tar.xz`;
|
|
32
|
+
if (verbose && !silent) {
|
|
33
|
+
console.log(`Downloading ${url}`);
|
|
34
|
+
}
|
|
35
|
+
await toolchainUtils.downloadAndExtract(url, path.join(cacheDir, version), "lintoko");
|
|
36
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Buffer } from "node:buffer";
|
|
2
|
+
export declare const TOOLCHAINS: string[];
|
|
2
3
|
export declare let tryDownloadFile: (url: string) => Promise<Buffer | null>;
|
|
3
4
|
export declare let downloadAndExtract: (url: string, destDir: string, destFileName?: string) => Promise<void>;
|
|
4
5
|
export declare let getLatestReleaseTag: (repo: string) => Promise<string>;
|
|
@@ -10,6 +10,7 @@ import { deleteSync } from "del";
|
|
|
10
10
|
import { Octokit } from "octokit";
|
|
11
11
|
import { extract as extractTar } from "tar";
|
|
12
12
|
import { getRootDir } from "../../mops.js";
|
|
13
|
+
export const TOOLCHAINS = ["moc", "wasmtime", "pocket-ic", "lintoko"];
|
|
13
14
|
export let tryDownloadFile = async (url) => {
|
|
14
15
|
let res = await fetch(url);
|
|
15
16
|
if (!res.ok) {
|
|
@@ -3,7 +3,7 @@ import { promisify } from "node:util";
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { getMocPath } from "../../helpers/get-moc-path.js";
|
|
6
|
-
import { getRootDir } from "../../mops.js";
|
|
6
|
+
import { getGlobalMocArgs, getRootDir, readConfig } from "../../mops.js";
|
|
7
7
|
import { sources } from "../sources.js";
|
|
8
8
|
import { parallel } from "../../parallel.js";
|
|
9
9
|
import { globMoFiles } from "./globMoFiles.js";
|
|
@@ -31,12 +31,18 @@ export class ErrorChecker {
|
|
|
31
31
|
let rootDir = getRootDir();
|
|
32
32
|
let mocPath = getMocPath();
|
|
33
33
|
let deps = await sources({ cwd: rootDir });
|
|
34
|
+
let globalMocArgs = getGlobalMocArgs(readConfig());
|
|
34
35
|
let paths = globMoFiles(rootDir);
|
|
35
36
|
this.totalFiles = paths.length;
|
|
36
37
|
this.processedFiles = 0;
|
|
37
38
|
await parallel(os.cpus().length, paths, async (file) => {
|
|
38
39
|
try {
|
|
39
|
-
await promisify(execFile)(mocPath, [
|
|
40
|
+
await promisify(execFile)(mocPath, [
|
|
41
|
+
"--check",
|
|
42
|
+
...deps.flatMap((x) => x.split(" ")),
|
|
43
|
+
...globalMocArgs,
|
|
44
|
+
file,
|
|
45
|
+
], { cwd: rootDir });
|
|
40
46
|
}
|
|
41
47
|
catch (error) {
|
|
42
48
|
error.message.split("\n").forEach((line) => {
|
|
@@ -3,7 +3,7 @@ import { promisify } from "node:util";
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { getMocPath } from "../../helpers/get-moc-path.js";
|
|
6
|
-
import { getRootDir } from "../../mops.js";
|
|
6
|
+
import { getGlobalMocArgs, getRootDir, readConfig } from "../../mops.js";
|
|
7
7
|
import { sources } from "../sources.js";
|
|
8
8
|
import { parallel } from "../../parallel.js";
|
|
9
9
|
import { globMoFiles } from "./globMoFiles.js";
|
|
@@ -51,6 +51,7 @@ export class WarningChecker {
|
|
|
51
51
|
let rootDir = getRootDir();
|
|
52
52
|
let mocPath = getMocPath();
|
|
53
53
|
let deps = await sources({ cwd: rootDir });
|
|
54
|
+
let globalMocArgs = getGlobalMocArgs(readConfig());
|
|
54
55
|
let paths = globMoFiles(rootDir);
|
|
55
56
|
this.totalFiles = paths.length;
|
|
56
57
|
this.processedFiles = 0;
|
|
@@ -58,7 +59,12 @@ export class WarningChecker {
|
|
|
58
59
|
let controller = new AbortController();
|
|
59
60
|
let { signal } = controller;
|
|
60
61
|
this.controllers.set(file, controller);
|
|
61
|
-
let { stderr } = await promisify(execFile)(mocPath, [
|
|
62
|
+
let { stderr } = await promisify(execFile)(mocPath, [
|
|
63
|
+
"--check",
|
|
64
|
+
...deps.flatMap((x) => x.split(" ")),
|
|
65
|
+
...globalMocArgs,
|
|
66
|
+
file,
|
|
67
|
+
], { cwd: rootDir, signal }).catch((error) => {
|
|
62
68
|
if (error.code === "ABORT_ERR") {
|
|
63
69
|
return { stderr: "" };
|
|
64
70
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common ignore patterns for glob operations across Motoko files.
|
|
3
|
+
*/
|
|
4
|
+
export declare const MOTOKO_IGNORE_PATTERNS: string[];
|
|
5
|
+
/**
|
|
6
|
+
* Common glob configuration for Motoko file operations
|
|
7
|
+
*/
|
|
8
|
+
export declare const MOTOKO_GLOB_CONFIG: {
|
|
9
|
+
nocase: boolean;
|
|
10
|
+
ignore: string[];
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Regex to match a file path for dependency and toolchain versions
|
|
14
|
+
*/
|
|
15
|
+
export declare const FILE_PATH_REGEX: RegExp;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common ignore patterns for glob operations across Motoko files.
|
|
3
|
+
*/
|
|
4
|
+
export const MOTOKO_IGNORE_PATTERNS = [
|
|
5
|
+
"**/node_modules/**",
|
|
6
|
+
"**/.mops/**",
|
|
7
|
+
"**/.vessel/**",
|
|
8
|
+
"**/.git/**",
|
|
9
|
+
"**/dist/**",
|
|
10
|
+
];
|
|
11
|
+
/**
|
|
12
|
+
* Common glob configuration for Motoko file operations
|
|
13
|
+
*/
|
|
14
|
+
export const MOTOKO_GLOB_CONFIG = {
|
|
15
|
+
nocase: true,
|
|
16
|
+
ignore: MOTOKO_IGNORE_PATTERNS,
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Regex to match a file path for dependency and toolchain versions
|
|
20
|
+
*/
|
|
21
|
+
export const FILE_PATH_REGEX = /^(\.?\.)?\//;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
2
4
|
import { setWasmBindings } from "../../wasm.js";
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
const wasm = require(path.join(__dirname, "../../wasm/pkg/nodejs/wasm.js"));
|
|
3
8
|
setWasmBindings(wasm);
|
|
4
9
|
export * from "../../cli.js";
|
package/dist/error.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function cliError(...args: unknown[]):
|
|
1
|
+
export declare function cliError(...args: unknown[]): never;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface MocSpan {
|
|
2
|
+
file: string;
|
|
3
|
+
line_start: number;
|
|
4
|
+
column_start: number;
|
|
5
|
+
line_end: number;
|
|
6
|
+
column_end: number;
|
|
7
|
+
is_primary: boolean;
|
|
8
|
+
label: string | null;
|
|
9
|
+
suggested_replacement: string | null;
|
|
10
|
+
suggestion_applicability: string | null;
|
|
11
|
+
}
|
|
12
|
+
export interface MocDiagnostic {
|
|
13
|
+
message: string;
|
|
14
|
+
code: string;
|
|
15
|
+
level: string;
|
|
16
|
+
spans: MocSpan[];
|
|
17
|
+
notes: string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function parseDiagnostics(stdout: string): MocDiagnostic[];
|
|
20
|
+
export interface AutofixResult {
|
|
21
|
+
/** Map of file path → diagnostic codes fixed in that file */
|
|
22
|
+
fixedFiles: Map<string, string[]>;
|
|
23
|
+
totalFixCount: number;
|
|
24
|
+
}
|
|
25
|
+
export declare function autofixMotoko(mocPath: string, files: string[], mocArgs: string[]): Promise<AutofixResult | null>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { execa } from "execa";
|
|
4
|
+
import { TextDocument, } from "vscode-languageserver-textdocument";
|
|
5
|
+
export function parseDiagnostics(stdout) {
|
|
6
|
+
return stdout
|
|
7
|
+
.split("\n")
|
|
8
|
+
.filter((l) => l.trim())
|
|
9
|
+
.map((l) => {
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(l);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
.filter((d) => d !== null);
|
|
18
|
+
}
|
|
19
|
+
function extractDiagnosticFixes(diagnostics) {
|
|
20
|
+
const result = new Map();
|
|
21
|
+
for (const diag of diagnostics) {
|
|
22
|
+
const editsByFile = new Map();
|
|
23
|
+
for (const span of diag.spans) {
|
|
24
|
+
if (span.suggestion_applicability === "MachineApplicable" &&
|
|
25
|
+
span.suggested_replacement !== null) {
|
|
26
|
+
const file = resolve(span.file);
|
|
27
|
+
const edits = editsByFile.get(file) ?? [];
|
|
28
|
+
edits.push({
|
|
29
|
+
range: {
|
|
30
|
+
start: {
|
|
31
|
+
line: span.line_start - 1,
|
|
32
|
+
character: span.column_start - 1,
|
|
33
|
+
},
|
|
34
|
+
end: {
|
|
35
|
+
line: span.line_end - 1,
|
|
36
|
+
character: span.column_end - 1,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
newText: span.suggested_replacement,
|
|
40
|
+
});
|
|
41
|
+
editsByFile.set(file, edits);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
for (const [file, edits] of editsByFile) {
|
|
45
|
+
const existing = result.get(file) ?? [];
|
|
46
|
+
existing.push({ code: diag.code, edits });
|
|
47
|
+
result.set(file, existing);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
function normalizeRange(range) {
|
|
53
|
+
const { start, end } = range;
|
|
54
|
+
if (start.line > end.line ||
|
|
55
|
+
(start.line === end.line && start.character > end.character)) {
|
|
56
|
+
return { start: end, end: start };
|
|
57
|
+
}
|
|
58
|
+
return range;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Applies diagnostic fixes to a document, processing each diagnostic as
|
|
62
|
+
* an atomic unit. If any edit from a diagnostic overlaps with an already-accepted
|
|
63
|
+
* edit, the entire diagnostic is skipped (picked up in subsequent iterations).
|
|
64
|
+
* Based on vscode-languageserver-textdocument's TextDocument.applyEdits.
|
|
65
|
+
*/
|
|
66
|
+
function applyDiagnosticFixes(doc, fixes) {
|
|
67
|
+
const acceptedEdits = [];
|
|
68
|
+
const appliedCodes = [];
|
|
69
|
+
for (const fix of fixes) {
|
|
70
|
+
const offsets = fix.edits.map((e) => {
|
|
71
|
+
const range = normalizeRange(e.range);
|
|
72
|
+
return {
|
|
73
|
+
start: doc.offsetAt(range.start),
|
|
74
|
+
end: doc.offsetAt(range.end),
|
|
75
|
+
newText: e.newText,
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
const overlaps = offsets.some((o) => acceptedEdits.some((a) => o.start < a.end && o.end > a.start));
|
|
79
|
+
if (overlaps) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
acceptedEdits.push(...offsets);
|
|
83
|
+
appliedCodes.push(fix.code);
|
|
84
|
+
}
|
|
85
|
+
acceptedEdits.sort((a, b) => a.start - b.start);
|
|
86
|
+
const text = doc.getText();
|
|
87
|
+
const spans = [];
|
|
88
|
+
let lastOffset = 0;
|
|
89
|
+
for (const edit of acceptedEdits) {
|
|
90
|
+
if (edit.start < lastOffset) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (edit.start > lastOffset) {
|
|
94
|
+
spans.push(text.substring(lastOffset, edit.start));
|
|
95
|
+
}
|
|
96
|
+
if (edit.newText.length) {
|
|
97
|
+
spans.push(edit.newText);
|
|
98
|
+
}
|
|
99
|
+
lastOffset = edit.end;
|
|
100
|
+
}
|
|
101
|
+
spans.push(text.substring(lastOffset));
|
|
102
|
+
return { text: spans.join(""), appliedCodes };
|
|
103
|
+
}
|
|
104
|
+
const MAX_FIX_ITERATIONS = 10;
|
|
105
|
+
export async function autofixMotoko(mocPath, files, mocArgs) {
|
|
106
|
+
const fixedFilesCodes = new Map();
|
|
107
|
+
for (let iteration = 0; iteration < MAX_FIX_ITERATIONS; iteration++) {
|
|
108
|
+
const fixesByFile = new Map();
|
|
109
|
+
for (const file of files) {
|
|
110
|
+
const result = await execa(mocPath, [file, ...mocArgs, "--error-format=json"], { stdio: "pipe", reject: false });
|
|
111
|
+
const diagnostics = parseDiagnostics(result.stdout);
|
|
112
|
+
for (const [targetFile, fixes] of extractDiagnosticFixes(diagnostics)) {
|
|
113
|
+
const existing = fixesByFile.get(targetFile) ?? [];
|
|
114
|
+
existing.push(...fixes);
|
|
115
|
+
fixesByFile.set(targetFile, existing);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (fixesByFile.size === 0) {
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
let progress = false;
|
|
122
|
+
for (const [file, fixes] of fixesByFile) {
|
|
123
|
+
const original = await readFile(file, "utf-8");
|
|
124
|
+
const doc = TextDocument.create(`file://${file}`, "motoko", 0, original);
|
|
125
|
+
const { text: result, appliedCodes } = applyDiagnosticFixes(doc, fixes);
|
|
126
|
+
if (result === original) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
await writeFile(file, result, "utf-8");
|
|
130
|
+
progress = true;
|
|
131
|
+
const existing = fixedFilesCodes.get(file) ?? [];
|
|
132
|
+
existing.push(...appliedCodes);
|
|
133
|
+
fixedFilesCodes.set(file, existing);
|
|
134
|
+
}
|
|
135
|
+
if (!progress) {
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (fixedFilesCodes.size === 0) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
let totalFixCount = 0;
|
|
143
|
+
for (const codes of fixedFilesCodes.values()) {
|
|
144
|
+
totalFixCount += codes.length;
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
fixedFiles: fixedFilesCodes,
|
|
148
|
+
totalFixCount,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { parse } from "semver";
|
|
3
|
+
import { readConfig } from "../mops.js";
|
|
2
4
|
import { getMocPath } from "./get-moc-path.js";
|
|
5
|
+
export function getMocSemVer() {
|
|
6
|
+
return parse(getMocVersion(false));
|
|
7
|
+
}
|
|
3
8
|
export function getMocVersion(throwOnError = false) {
|
|
4
|
-
let
|
|
9
|
+
let configVersion = readConfig().toolchain?.moc;
|
|
10
|
+
if (configVersion) {
|
|
11
|
+
return configVersion;
|
|
12
|
+
}
|
|
13
|
+
const mocPath = getMocPath(false);
|
|
5
14
|
if (!mocPath) {
|
|
6
15
|
return "";
|
|
7
16
|
}
|
package/dist/mops.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export declare function getGithubCommit(repo: string, ref: string): Promise<any>
|
|
|
23
23
|
export declare function getDependencyType(version: string): "local" | "mops" | "github";
|
|
24
24
|
export declare function parseDepValue(name: string, value: string): Dependency;
|
|
25
25
|
export declare function readConfig(configFile?: string): Config;
|
|
26
|
+
export declare function getGlobalMocArgs(config: Config): string[];
|
|
26
27
|
export declare function writeConfig(config: Config, configFile?: string): void;
|
|
27
28
|
export declare function formatDir(name: string, version: string): string;
|
|
28
29
|
export declare function formatGithubDir(name: string, repo: string): string;
|
package/dist/mops.js
CHANGED
|
@@ -6,10 +6,12 @@ import chalk from "chalk";
|
|
|
6
6
|
import prompts from "prompts";
|
|
7
7
|
import fetch from "node-fetch";
|
|
8
8
|
import { decodeFile } from "./pem.js";
|
|
9
|
+
import { cliError } from "./error.js";
|
|
9
10
|
import { mainActor, storageActor } from "./api/actors.js";
|
|
10
11
|
import { getNetwork } from "./api/network.js";
|
|
11
12
|
import { getHighestVersion } from "./api/getHighestVersion.js";
|
|
12
13
|
import { getPackageId } from "./helpers/get-package-id.js";
|
|
14
|
+
import { FILE_PATH_REGEX } from "./constants.js";
|
|
13
15
|
if (!globalThis.fetch) {
|
|
14
16
|
globalThis.fetch = fetch;
|
|
15
17
|
}
|
|
@@ -135,7 +137,7 @@ export function getDependencyType(version) {
|
|
|
135
137
|
if (version.startsWith("https://github.com/")) {
|
|
136
138
|
return "github";
|
|
137
139
|
}
|
|
138
|
-
else if (version.match(
|
|
140
|
+
else if (version.match(FILE_PATH_REGEX)) {
|
|
139
141
|
return "local";
|
|
140
142
|
}
|
|
141
143
|
else {
|
|
@@ -176,6 +178,15 @@ export function readConfig(configFile = getClosestConfigFile()) {
|
|
|
176
178
|
});
|
|
177
179
|
return config;
|
|
178
180
|
}
|
|
181
|
+
export function getGlobalMocArgs(config) {
|
|
182
|
+
if (!config.moc?.args) {
|
|
183
|
+
return [];
|
|
184
|
+
}
|
|
185
|
+
if (typeof config.moc.args === "string") {
|
|
186
|
+
cliError(`[moc] config 'args' should be an array of strings in mops.toml config file`);
|
|
187
|
+
}
|
|
188
|
+
return config.moc.args;
|
|
189
|
+
}
|
|
179
190
|
export function writeConfig(config, configFile = getClosestConfigFile()) {
|
|
180
191
|
let resConfig = JSON.parse(JSON.stringify(config));
|
|
181
192
|
let deps = resConfig.dependencies || {};
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ic-mops",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mops": "bin/mops.js",
|
|
@@ -71,7 +71,8 @@
|
|
|
71
71
|
"stream-to-promise": "3.0.0",
|
|
72
72
|
"string-width": "7.2.0",
|
|
73
73
|
"tar": "7.5.6",
|
|
74
|
-
"terminal-size": "4.0.0"
|
|
74
|
+
"terminal-size": "4.0.0",
|
|
75
|
+
"vscode-languageserver-textdocument": "1.0.12"
|
|
75
76
|
},
|
|
76
77
|
"devDependencies": {
|
|
77
78
|
"@tsconfig/strictest": "2.0.5",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { describe, test } from "@jest/globals";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { cliSnapshot } from "./helpers";
|
|
4
|
+
describe("build without dfx", () => {
|
|
5
|
+
test("builds using mops toolchain moc", async () => {
|
|
6
|
+
const cwd = path.join(import.meta.dirname, "build/no-dfx");
|
|
7
|
+
await cliSnapshot(["build"], { cwd }, 0);
|
|
8
|
+
}, 120_000);
|
|
9
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { cliSnapshot } from "./helpers";
|
|
4
|
+
describe("build", () => {
|
|
5
|
+
test("ok", async () => {
|
|
6
|
+
const cwd = path.join(import.meta.dirname, "build/success");
|
|
7
|
+
await cliSnapshot(["build", "--verbose"], { cwd }, 0);
|
|
8
|
+
await cliSnapshot(["build", "foo"], { cwd }, 0);
|
|
9
|
+
await cliSnapshot(["build", "bar"], { cwd }, 0);
|
|
10
|
+
await cliSnapshot(["build", "foo", "bar"], { cwd }, 0);
|
|
11
|
+
});
|
|
12
|
+
test("error", async () => {
|
|
13
|
+
const cwd = path.join(import.meta.dirname, "build/error");
|
|
14
|
+
await cliSnapshot(["build", "foo", "--verbose"], { cwd }, 0);
|
|
15
|
+
expect((await cliSnapshot(["build", "bar"], { cwd }, 1)).stderr).toMatch("Candid compatibility check failed for canister bar");
|
|
16
|
+
expect((await cliSnapshot(["build", "foo", "bar"], { cwd }, 1)).stderr).toMatch("Candid compatibility check failed for canister bar");
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { describe, test } from "@jest/globals";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { cliSnapshot } from "./helpers";
|
|
4
|
+
describe("check-candid", () => {
|
|
5
|
+
test("ok", async () => {
|
|
6
|
+
const cwd = path.join(import.meta.dirname, "check-candid");
|
|
7
|
+
await cliSnapshot(["check-candid", "a.did", "a.did"], { cwd }, 0);
|
|
8
|
+
await cliSnapshot(["check-candid", "b.did", "b.did"], { cwd }, 0);
|
|
9
|
+
await cliSnapshot(["check-candid", "c.did", "c.did"], { cwd }, 0);
|
|
10
|
+
await cliSnapshot(["check-candid", "a.did", "b.did"], { cwd }, 0);
|
|
11
|
+
await cliSnapshot(["check-candid", "b.did", "a.did"], { cwd }, 0);
|
|
12
|
+
});
|
|
13
|
+
test("error", async () => {
|
|
14
|
+
const cwd = path.join(import.meta.dirname, "check-candid");
|
|
15
|
+
await cliSnapshot(["check-candid", "a.did", "c.did"], { cwd }, 1);
|
|
16
|
+
await cliSnapshot(["check-candid", "c.did", "a.did"], { cwd }, 1);
|
|
17
|
+
await cliSnapshot(["check-candid", "b.did", "c.did"], { cwd }, 1);
|
|
18
|
+
await cliSnapshot(["check-candid", "c.did", "b.did"], { cwd }, 1);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|