ic-mops 2.8.1 → 2.9.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 +4 -0
- package/bundle/cli.tgz +0 -0
- package/cli.ts +11 -1
- package/commands/build.ts +127 -92
- package/commands/info.ts +103 -0
- package/commands/lint.ts +132 -42
- package/commands/toolchain/moc.ts +5 -5
- package/dist/cli.js +9 -0
- package/dist/commands/build.js +102 -69
- package/dist/commands/info.d.ts +4 -0
- package/dist/commands/info.js +75 -0
- package/dist/commands/lint.js +84 -37
- package/dist/commands/toolchain/moc.js +5 -5
- package/dist/package.json +3 -1
- package/dist/templates/mops-publish.yml +1 -1
- package/dist/templates/mops-test.yml +1 -1
- package/dist/tests/build.test.js +17 -0
- package/dist/tests/lint.test.js +33 -0
- package/dist/types.d.ts +1 -0
- package/dist/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
- package/dist/wasm/pkg/web/wasm_bg.wasm +0 -0
- package/package.json +3 -1
- package/templates/mops-publish.yml +1 -1
- package/templates/mops-test.yml +1 -1
- package/tests/__snapshots__/lint.test.ts.snap +163 -5
- package/tests/build.test.ts +17 -0
- package/tests/lint-extra/mops.toml +5 -0
- package/tests/lint-extra/src/Ok.mo +5 -0
- package/tests/lint-extra/src/restricted/B.mo +8 -0
- package/tests/lint-extra/src/restricted/Restricted.mo +8 -0
- package/tests/lint-extra-edge-cases/mops.toml +8 -0
- package/tests/lint-extra-edge-cases/src/Clean.mo +5 -0
- package/tests/lint-extra-example-rules/lint/migration-only/migration-only.toml +9 -0
- package/tests/lint-extra-example-rules/lint/no-types/no-types.toml +5 -0
- package/tests/lint-extra-example-rules/lint/types-only/types-only.toml +6 -0
- package/tests/lint-extra-example-rules/mops.toml +7 -0
- package/tests/lint-extra-example-rules/src/Main.mo +10 -0
- package/tests/lint-extra-example-rules/src/Migration.mo +9 -0
- package/tests/lint-extra-example-rules/src/Types.mo +10 -0
- package/tests/lint-extra-with-base/mops.toml +8 -0
- package/tests/lint-extra-with-base/src/BadBase.mo +8 -0
- package/tests/lint-extra-with-base/src/Ok.mo +5 -0
- package/tests/lint-extra-with-base/src/Restricted.mo +5 -0
- package/tests/lint-extra-with-cli-rules/empty-rules/.gitkeep +0 -0
- package/tests/lint-extra-with-cli-rules/mops.toml +5 -0
- package/tests/lint-extra-with-cli-rules/rules-b/no-bool-switch-2.toml +9 -0
- package/tests/lint-extra-with-cli-rules/src/Ok.mo +5 -0
- package/tests/lint-extra-with-cli-rules/src/Restricted.mo +8 -0
- package/tests/lint.test.ts +42 -0
- package/types.ts +1 -0
- package/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
- package/wasm/pkg/web/wasm_bg.wasm +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Next
|
|
4
4
|
|
|
5
|
+
## 2.9.0
|
|
6
|
+
- Add `mops info <pkg>` command to show detailed package metadata from the registry
|
|
7
|
+
- Add `[lint.extra]` config for applying additional lint rules to specific files via glob patterns
|
|
8
|
+
|
|
5
9
|
## 2.8.1
|
|
6
10
|
|
|
7
11
|
- Fix `mops check-stable` failing when `[moc] args` contains flags with relative paths (e.g. `--actor-idl=system-idl`)
|
package/bundle/cli.tgz
CHANGED
|
Binary file
|
package/cli.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { getNetwork } from "./api/network.js";
|
|
|
8
8
|
import { cacheSize, cleanCache, show } from "./cache.js";
|
|
9
9
|
import { add } from "./commands/add.js";
|
|
10
10
|
import { bench } from "./commands/bench.js";
|
|
11
|
-
import { build
|
|
11
|
+
import { build } from "./commands/build.js";
|
|
12
12
|
import { bump } from "./commands/bump.js";
|
|
13
13
|
import { check } from "./commands/check.js";
|
|
14
14
|
import { checkCandid } from "./commands/check-candid.js";
|
|
@@ -16,6 +16,7 @@ import { checkStable } from "./commands/check-stable.js";
|
|
|
16
16
|
import { docsCoverage } from "./commands/docs-coverage.js";
|
|
17
17
|
import { docs } from "./commands/docs.js";
|
|
18
18
|
import { format } from "./commands/format.js";
|
|
19
|
+
import { info } from "./commands/info.js";
|
|
19
20
|
import { init } from "./commands/init.js";
|
|
20
21
|
import { lint } from "./commands/lint.js";
|
|
21
22
|
import { installAll } from "./commands/install/install-all.js";
|
|
@@ -279,6 +280,15 @@ program
|
|
|
279
280
|
await search(text);
|
|
280
281
|
});
|
|
281
282
|
|
|
283
|
+
// info
|
|
284
|
+
program
|
|
285
|
+
.command("info <pkg>")
|
|
286
|
+
.description("Show detailed information about a package from the registry")
|
|
287
|
+
.option("--versions", "List all published versions, one per line")
|
|
288
|
+
.action(async (pkg: string, options) => {
|
|
289
|
+
await info(pkg, options);
|
|
290
|
+
});
|
|
291
|
+
|
|
282
292
|
// cache
|
|
283
293
|
program
|
|
284
294
|
.command("cache")
|
package/commands/build.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { execa } from "execa";
|
|
|
3
3
|
import { exists } from "fs-extra";
|
|
4
4
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
5
5
|
import { join } from "node:path";
|
|
6
|
+
import { lock, unlockSync } from "proper-lockfile";
|
|
6
7
|
import { cliError } from "../error.js";
|
|
7
8
|
import { isCandidCompatible } from "../helpers/is-candid-compatible.js";
|
|
8
9
|
import { resolveCanisterConfigs } from "../helpers/resolve-canisters.js";
|
|
@@ -70,115 +71,149 @@ export async function build(
|
|
|
70
71
|
motokoPath = resolveConfigPath(motokoPath);
|
|
71
72
|
const wasmPath = join(outputDir, `${canisterName}.wasm`);
|
|
72
73
|
const mostPath = join(outputDir, `${canisterName}.most`);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const candidVisibility = isPublicCandid ? "icp:public" : "icp:private";
|
|
89
|
-
if (isPublicCandid) {
|
|
90
|
-
args.push("--public-metadata", "candid:service");
|
|
91
|
-
args.push("--public-metadata", "candid:args");
|
|
74
|
+
|
|
75
|
+
// per-canister lock to prevent parallel builds of the same canister from clobbering output files
|
|
76
|
+
const lockTarget = join(outputDir, `.${canisterName}.buildlock`);
|
|
77
|
+
await writeFile(lockTarget, "", { flag: "a" });
|
|
78
|
+
|
|
79
|
+
let release: (() => Promise<void>) | undefined;
|
|
80
|
+
try {
|
|
81
|
+
release = await lock(lockTarget, {
|
|
82
|
+
stale: 300_000,
|
|
83
|
+
retries: { retries: 60, minTimeout: 500, maxTimeout: 5_000 },
|
|
84
|
+
});
|
|
85
|
+
} catch {
|
|
86
|
+
cliError(
|
|
87
|
+
`Failed to acquire build lock for canister ${canisterName} — another build may be stuck`,
|
|
88
|
+
);
|
|
92
89
|
}
|
|
90
|
+
|
|
91
|
+
// proper-lockfile registers its own signal-exit handler, but it doesn't reliably
|
|
92
|
+
// fire on process.exit(). This manual handler covers that gap. Double-unlock is
|
|
93
|
+
// harmless (the second call throws and is caught).
|
|
94
|
+
const exitCleanup = () => {
|
|
95
|
+
try {
|
|
96
|
+
unlockSync(lockTarget);
|
|
97
|
+
} catch {}
|
|
98
|
+
};
|
|
99
|
+
process.on("exit", exitCleanup);
|
|
100
|
+
|
|
93
101
|
try {
|
|
94
|
-
|
|
95
|
-
|
|
102
|
+
let args = [
|
|
103
|
+
"-c",
|
|
104
|
+
"--idl",
|
|
105
|
+
"--stable-types",
|
|
106
|
+
"-o",
|
|
107
|
+
wasmPath,
|
|
108
|
+
motokoPath,
|
|
109
|
+
...(await sourcesArgs()).flat(),
|
|
110
|
+
...getGlobalMocArgs(config),
|
|
111
|
+
];
|
|
112
|
+
args.push(
|
|
113
|
+
...collectExtraArgs(config, canister, canisterName, options.extraArgs),
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const isPublicCandid = true; // always true for now to reduce corner cases
|
|
117
|
+
const candidVisibility = isPublicCandid ? "icp:public" : "icp:private";
|
|
118
|
+
if (isPublicCandid) {
|
|
119
|
+
args.push("--public-metadata", "candid:service");
|
|
120
|
+
args.push("--public-metadata", "candid:args");
|
|
96
121
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
122
|
+
try {
|
|
123
|
+
if (options.verbose) {
|
|
124
|
+
console.log(chalk.gray(mocPath, JSON.stringify(args)));
|
|
125
|
+
}
|
|
126
|
+
const result = await execa(mocPath, args, {
|
|
127
|
+
stdio: options.verbose ? "inherit" : "pipe",
|
|
128
|
+
reject: false,
|
|
129
|
+
});
|
|
101
130
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
131
|
+
if (result.exitCode !== 0) {
|
|
132
|
+
if (!options.verbose) {
|
|
133
|
+
if (result.stderr) {
|
|
134
|
+
console.error(chalk.red(result.stderr));
|
|
135
|
+
}
|
|
136
|
+
if (result.stdout?.trim()) {
|
|
137
|
+
console.error(chalk.yellow("Build output:"));
|
|
138
|
+
console.error(result.stdout);
|
|
139
|
+
}
|
|
110
140
|
}
|
|
141
|
+
cliError(
|
|
142
|
+
`Build failed for canister ${canisterName} (exit code: ${result.exitCode})`,
|
|
143
|
+
);
|
|
111
144
|
}
|
|
112
|
-
cliError(
|
|
113
|
-
`Build failed for canister ${canisterName} (exit code: ${result.exitCode})`,
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (options.verbose && result.stdout && result.stdout.trim()) {
|
|
118
|
-
console.log(result.stdout);
|
|
119
|
-
}
|
|
120
145
|
|
|
121
|
-
|
|
122
|
-
|
|
146
|
+
if (options.verbose && result.stdout && result.stdout.trim()) {
|
|
147
|
+
console.log(result.stdout);
|
|
148
|
+
}
|
|
123
149
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
? resolveConfigPath(canister.candid)
|
|
127
|
-
: null;
|
|
150
|
+
options.verbose &&
|
|
151
|
+
console.log(chalk.gray(`Stable types written to ${mostPath}`));
|
|
128
152
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
resolvedCandidPath,
|
|
134
|
-
);
|
|
153
|
+
const generatedDidPath = join(outputDir, `${canisterName}.did`);
|
|
154
|
+
const resolvedCandidPath = canister.candid
|
|
155
|
+
? resolveConfigPath(canister.candid)
|
|
156
|
+
: null;
|
|
135
157
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
158
|
+
if (resolvedCandidPath) {
|
|
159
|
+
try {
|
|
160
|
+
const compatible = await isCandidCompatible(
|
|
161
|
+
generatedDidPath,
|
|
162
|
+
resolvedCandidPath,
|
|
139
163
|
);
|
|
140
|
-
}
|
|
141
164
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
165
|
+
if (!compatible) {
|
|
166
|
+
cliError(
|
|
167
|
+
`Candid compatibility check failed for canister ${canisterName}`,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (options.verbose) {
|
|
172
|
+
console.log(
|
|
173
|
+
chalk.gray(
|
|
174
|
+
`Candid compatibility check passed for canister ${canisterName}`,
|
|
175
|
+
),
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
} catch (err: any) {
|
|
179
|
+
cliError(
|
|
180
|
+
`Error during Candid compatibility check for canister ${canisterName}${err?.message ? `\n${err.message}` : ""}`,
|
|
147
181
|
);
|
|
148
182
|
}
|
|
149
|
-
} catch (err: any) {
|
|
150
|
-
cliError(
|
|
151
|
-
`Error during Candid compatibility check for canister ${canisterName}${err?.message ? `\n${err.message}` : ""}`,
|
|
152
|
-
);
|
|
153
183
|
}
|
|
154
|
-
}
|
|
155
184
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
185
|
+
options.verbose &&
|
|
186
|
+
console.log(chalk.gray(`Adding metadata to ${wasmPath}`));
|
|
187
|
+
const candidPath = resolvedCandidPath ?? generatedDidPath;
|
|
188
|
+
const candidText = await readFile(candidPath, "utf-8");
|
|
189
|
+
const customSections: CustomSection[] = [
|
|
190
|
+
{ name: `${candidVisibility} candid:service`, data: candidText },
|
|
191
|
+
];
|
|
192
|
+
if (canister.initArg) {
|
|
193
|
+
customSections.push({
|
|
194
|
+
name: `${candidVisibility} candid:args`,
|
|
195
|
+
data: canister.initArg,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
const wasmBytes = await readFile(wasmPath);
|
|
199
|
+
const newWasm = getWasmBindings().add_custom_sections(
|
|
200
|
+
wasmBytes,
|
|
201
|
+
customSections,
|
|
202
|
+
);
|
|
203
|
+
await writeFile(wasmPath, newWasm);
|
|
204
|
+
} catch (err: any) {
|
|
205
|
+
if (err.message?.includes("Build failed for canister")) {
|
|
206
|
+
throw err;
|
|
207
|
+
}
|
|
208
|
+
cliError(
|
|
209
|
+
`Error while compiling canister ${canisterName}${err?.message ? `\n${err.message}` : ""}`,
|
|
210
|
+
);
|
|
178
211
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
212
|
+
} finally {
|
|
213
|
+
process.removeListener("exit", exitCleanup);
|
|
214
|
+
try {
|
|
215
|
+
await release?.();
|
|
216
|
+
} catch {}
|
|
182
217
|
}
|
|
183
218
|
}
|
|
184
219
|
|
package/commands/info.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { mainActor } from "../api/actors.js";
|
|
4
|
+
import { resolveVersion } from "../api/resolveVersion.js";
|
|
5
|
+
import type { PackageDetails } from "../declarations/main/main.did.js";
|
|
6
|
+
|
|
7
|
+
function label(text: string): string {
|
|
8
|
+
return chalk.bold(text.padEnd(16));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface InfoOptions {
|
|
12
|
+
versions?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function info(pkgArg: string, options: InfoOptions = {}) {
|
|
16
|
+
let [name, versionArg] = pkgArg.split("@") as [string, string | undefined];
|
|
17
|
+
let actor = await mainActor();
|
|
18
|
+
|
|
19
|
+
let version: string;
|
|
20
|
+
try {
|
|
21
|
+
version = await resolveVersion(name, versionArg ?? "");
|
|
22
|
+
} catch (err) {
|
|
23
|
+
let message = err instanceof Error ? err.message : String(err);
|
|
24
|
+
console.error(chalk.red("Error: ") + message);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let res = await actor.getPackageDetails(name, version);
|
|
29
|
+
if ("err" in res) {
|
|
30
|
+
console.error(chalk.red("Error: ") + res.err);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let d: PackageDetails = res.ok;
|
|
35
|
+
let c = d.config;
|
|
36
|
+
|
|
37
|
+
// d.versions is in ascending order (oldest first)
|
|
38
|
+
if (options.versions) {
|
|
39
|
+
for (let ver of d.versions) {
|
|
40
|
+
console.log(ver);
|
|
41
|
+
}
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log("");
|
|
46
|
+
console.log(
|
|
47
|
+
`${chalk.green.bold(c.name)}${chalk.gray("@")}${chalk.yellow(c.version)}`,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (c.description) {
|
|
51
|
+
console.log(chalk.dim(c.description));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (c.version !== d.highestVersion) {
|
|
55
|
+
console.log(chalk.yellow(`latest: ${d.highestVersion}`));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log("");
|
|
59
|
+
|
|
60
|
+
if (c.license) {
|
|
61
|
+
console.log(`${label("license")}${c.license}`);
|
|
62
|
+
}
|
|
63
|
+
if (c.repository) {
|
|
64
|
+
console.log(`${label("repository")}${chalk.cyan(c.repository)}`);
|
|
65
|
+
}
|
|
66
|
+
if (c.homepage) {
|
|
67
|
+
console.log(`${label("homepage")}${chalk.cyan(c.homepage)}`);
|
|
68
|
+
}
|
|
69
|
+
if (c.documentation) {
|
|
70
|
+
console.log(`${label("documentation")}${chalk.cyan(c.documentation)}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (c.dependencies.length > 0) {
|
|
74
|
+
console.log("");
|
|
75
|
+
console.log(
|
|
76
|
+
`${label("dependencies")}${c.dependencies.map((dep) => `${dep.name}${chalk.gray("@")}${dep.version || dep.repo}`).join(", ")}`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
if (c.devDependencies.length > 0) {
|
|
80
|
+
console.log(
|
|
81
|
+
`${label("dev-deps")}${c.devDependencies.map((dep) => `${dep.name}${chalk.gray("@")}${dep.version || dep.repo}`).join(", ")}`,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (c.keywords.length > 0) {
|
|
86
|
+
console.log("");
|
|
87
|
+
console.log(
|
|
88
|
+
`${label("keywords")}${c.keywords.map((k) => chalk.yellow(k)).join(", ")}`,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (d.versions.length > 0) {
|
|
93
|
+
let versionsDisplay = d.versions.slice(-10).reverse().join(", ");
|
|
94
|
+
let extra =
|
|
95
|
+
d.versions.length > 10
|
|
96
|
+
? ` ${chalk.gray(`(+${d.versions.length - 10} more)`)}`
|
|
97
|
+
: "";
|
|
98
|
+
console.log("");
|
|
99
|
+
console.log(`${label("versions")}${versionsDisplay}${extra}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
console.log("");
|
|
103
|
+
}
|
package/commands/lint.ts
CHANGED
|
@@ -103,6 +103,62 @@ export interface LintOptions {
|
|
|
103
103
|
extraArgs: string[];
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
function buildCommonArgs(
|
|
107
|
+
options: Partial<LintOptions>,
|
|
108
|
+
config: Config,
|
|
109
|
+
): string[] {
|
|
110
|
+
const args: string[] = [];
|
|
111
|
+
if (options.verbose) {
|
|
112
|
+
args.push("--verbose");
|
|
113
|
+
}
|
|
114
|
+
if (options.fix) {
|
|
115
|
+
args.push("--fix");
|
|
116
|
+
}
|
|
117
|
+
if (config.lint?.args) {
|
|
118
|
+
if (typeof config.lint.args === "string") {
|
|
119
|
+
cliError(
|
|
120
|
+
`[lint] config 'args' should be an array of strings in mops.toml config file`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
args.push(...config.lint.args);
|
|
124
|
+
}
|
|
125
|
+
if (options.extraArgs && options.extraArgs.length > 0) {
|
|
126
|
+
args.push(...options.extraArgs);
|
|
127
|
+
}
|
|
128
|
+
return args;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function runLintoko(
|
|
132
|
+
lintokoBinPath: string,
|
|
133
|
+
rootDir: string,
|
|
134
|
+
args: string[],
|
|
135
|
+
options: Partial<LintOptions>,
|
|
136
|
+
label: string,
|
|
137
|
+
): Promise<boolean> {
|
|
138
|
+
try {
|
|
139
|
+
if (options.verbose) {
|
|
140
|
+
console.log(
|
|
141
|
+
chalk.blue("lint"),
|
|
142
|
+
chalk.gray(`Running lintoko (${label}):`),
|
|
143
|
+
);
|
|
144
|
+
console.log(chalk.gray(lintokoBinPath));
|
|
145
|
+
console.log(chalk.gray(JSON.stringify(args)));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const result = await execa(lintokoBinPath, args, {
|
|
149
|
+
cwd: rootDir,
|
|
150
|
+
stdio: "inherit",
|
|
151
|
+
reject: false,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
return result.exitCode === 0;
|
|
155
|
+
} catch (err: any) {
|
|
156
|
+
cliError(
|
|
157
|
+
`Error while running lintoko${err?.message ? `\n${err.message}` : ""}`,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
106
162
|
export async function lint(
|
|
107
163
|
filter: string | undefined,
|
|
108
164
|
options: Partial<LintOptions>,
|
|
@@ -131,59 +187,93 @@ export async function lint(
|
|
|
131
187
|
}
|
|
132
188
|
}
|
|
133
189
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (options.fix) {
|
|
139
|
-
args.push("--fix");
|
|
140
|
-
}
|
|
190
|
+
const commonArgs = buildCommonArgs(options, config);
|
|
191
|
+
|
|
192
|
+
// --- base run ---
|
|
193
|
+
const baseArgs: string[] = [...commonArgs];
|
|
141
194
|
const rules =
|
|
142
195
|
options.rules !== undefined
|
|
143
196
|
? options.rules
|
|
144
197
|
: await collectLintRules(config, rootDir);
|
|
145
|
-
rules.forEach((rule) =>
|
|
198
|
+
rules.forEach((rule) => baseArgs.push("--rules", rule));
|
|
199
|
+
baseArgs.push(...filesToLint);
|
|
146
200
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
201
|
+
let failed = !(await runLintoko(
|
|
202
|
+
lintokoBinPath,
|
|
203
|
+
rootDir,
|
|
204
|
+
baseArgs,
|
|
205
|
+
options,
|
|
206
|
+
"base",
|
|
207
|
+
));
|
|
155
208
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
209
|
+
// --- extra runs ---
|
|
210
|
+
const extraEntries = config.lint?.extra;
|
|
211
|
+
if (extraEntries) {
|
|
212
|
+
const isFiltered = filter || (options.files && options.files.length > 0);
|
|
213
|
+
const baseFileSet = isFiltered
|
|
214
|
+
? new Set(filesToLint.map((f) => path.resolve(rootDir, f)))
|
|
215
|
+
: undefined;
|
|
159
216
|
|
|
160
|
-
|
|
217
|
+
for (const [globPattern, ruleDirs] of Object.entries(extraEntries)) {
|
|
218
|
+
if (!Array.isArray(ruleDirs) || ruleDirs.length === 0) {
|
|
219
|
+
console.warn(
|
|
220
|
+
chalk.yellow(
|
|
221
|
+
`[lint.extra] skipping '${globPattern}': value must be a non-empty array of rule directories`,
|
|
222
|
+
),
|
|
223
|
+
);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
161
226
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
227
|
+
for (const dir of ruleDirs) {
|
|
228
|
+
if (!existsSync(path.join(rootDir, dir))) {
|
|
229
|
+
cliError(
|
|
230
|
+
`[lint.extra] rule directory '${dir}' not found (referenced by glob '${globPattern}')`,
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
168
234
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
});
|
|
235
|
+
let matchedFiles = globSync(path.join(rootDir, globPattern), {
|
|
236
|
+
...MOTOKO_GLOB_CONFIG,
|
|
237
|
+
cwd: rootDir,
|
|
238
|
+
});
|
|
174
239
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
240
|
+
if (baseFileSet) {
|
|
241
|
+
matchedFiles = matchedFiles.filter((f) =>
|
|
242
|
+
baseFileSet.has(path.resolve(rootDir, f)),
|
|
243
|
+
);
|
|
244
|
+
}
|
|
178
245
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
246
|
+
if (matchedFiles.length === 0) {
|
|
247
|
+
console.warn(
|
|
248
|
+
chalk.yellow(
|
|
249
|
+
`[lint.extra] no files matched glob '${globPattern}', skipping`,
|
|
250
|
+
),
|
|
251
|
+
);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const extraArgs: string[] = [...commonArgs];
|
|
256
|
+
for (const dir of ruleDirs) {
|
|
257
|
+
extraArgs.push("--rules", dir);
|
|
258
|
+
}
|
|
259
|
+
extraArgs.push(...matchedFiles);
|
|
260
|
+
|
|
261
|
+
const passed = await runLintoko(
|
|
262
|
+
lintokoBinPath,
|
|
263
|
+
rootDir,
|
|
264
|
+
extraArgs,
|
|
265
|
+
options,
|
|
266
|
+
`extra: ${globPattern}`,
|
|
267
|
+
);
|
|
268
|
+
failed ||= !passed;
|
|
183
269
|
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (failed) {
|
|
273
|
+
cliError("Lint failed");
|
|
274
|
+
} else if (options.fix) {
|
|
275
|
+
console.log(chalk.green("✓ Lint fixes applied"));
|
|
276
|
+
} else {
|
|
277
|
+
console.log(chalk.green("✓ Lint succeeded"));
|
|
188
278
|
}
|
|
189
279
|
}
|
|
@@ -8,7 +8,7 @@ import * as toolchainUtils from "./toolchain-utils.js";
|
|
|
8
8
|
|
|
9
9
|
let cacheDir = path.join(globalCacheDir, "moc");
|
|
10
10
|
|
|
11
|
-
export let repo = "
|
|
11
|
+
export let repo = "caffeinelabs/motoko";
|
|
12
12
|
|
|
13
13
|
export let getLatestReleaseTag = async () => {
|
|
14
14
|
return toolchainUtils.getLatestReleaseTag(repo);
|
|
@@ -44,7 +44,7 @@ export let download = async (
|
|
|
44
44
|
}
|
|
45
45
|
} else {
|
|
46
46
|
// Download the .js artifact
|
|
47
|
-
const jsUrl = `https://github.com/
|
|
47
|
+
const jsUrl = `https://github.com/caffeinelabs/motoko/releases/download/${version}/moc-${version}.js`;
|
|
48
48
|
const jsDestPath = path.join(destDir, "moc.js");
|
|
49
49
|
|
|
50
50
|
if (verbose && !silent) {
|
|
@@ -75,14 +75,14 @@ export let download = async (
|
|
|
75
75
|
? "arm64"
|
|
76
76
|
: "aarch64"
|
|
77
77
|
: "x86_64";
|
|
78
|
-
url = `https://github.com/
|
|
78
|
+
url = `https://github.com/caffeinelabs/motoko/releases/download/${version}/motoko-${platfrom}-${arch}-${version}.tar.gz`;
|
|
79
79
|
} else if (new SemVer(version).compare(new SemVer("0.9.5")) >= 0) {
|
|
80
80
|
let platfrom = process.platform == "darwin" ? "Darwin" : "Linux";
|
|
81
81
|
let arch = "x86_64";
|
|
82
|
-
url = `https://github.com/
|
|
82
|
+
url = `https://github.com/caffeinelabs/motoko/releases/download/${version}/motoko-${platfrom}-${arch}-${version}.tar.gz`;
|
|
83
83
|
} else {
|
|
84
84
|
let platfrom = process.platform == "darwin" ? "macos" : "linux64";
|
|
85
|
-
url = `https://github.com/
|
|
85
|
+
url = `https://github.com/caffeinelabs/motoko/releases/download/${version}/motoko-${platfrom}-${version}.tar.gz`;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
if (verbose && !silent) {
|
package/dist/cli.js
CHANGED
|
@@ -15,6 +15,7 @@ import { checkStable } from "./commands/check-stable.js";
|
|
|
15
15
|
import { docsCoverage } from "./commands/docs-coverage.js";
|
|
16
16
|
import { docs } from "./commands/docs.js";
|
|
17
17
|
import { format } from "./commands/format.js";
|
|
18
|
+
import { info } from "./commands/info.js";
|
|
18
19
|
import { init } from "./commands/init.js";
|
|
19
20
|
import { lint } from "./commands/lint.js";
|
|
20
21
|
import { installAll } from "./commands/install/install-all.js";
|
|
@@ -213,6 +214,14 @@ program
|
|
|
213
214
|
.action(async (text) => {
|
|
214
215
|
await search(text);
|
|
215
216
|
});
|
|
217
|
+
// info
|
|
218
|
+
program
|
|
219
|
+
.command("info <pkg>")
|
|
220
|
+
.description("Show detailed information about a package from the registry")
|
|
221
|
+
.option("--versions", "List all published versions, one per line")
|
|
222
|
+
.action(async (pkg, options) => {
|
|
223
|
+
await info(pkg, options);
|
|
224
|
+
});
|
|
216
225
|
// cache
|
|
217
226
|
program
|
|
218
227
|
.command("cache")
|