ic-mops 2.15.2 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/bundle/cli.tgz +0 -0
- package/check-requirements.ts +53 -31
- package/cli.ts +12 -0
- package/commands/bench.ts +23 -5
- package/commands/toolchain/index.ts +1 -3
- package/dist/check-requirements.js +31 -24
- package/dist/cli.js +2 -0
- package/dist/commands/bench.d.ts +2 -0
- package/dist/commands/bench.js +16 -3
- package/dist/commands/toolchain/index.js +1 -3
- package/dist/helpers/get-lintoko-version.d.ts +3 -0
- package/dist/helpers/get-lintoko-version.js +30 -0
- package/dist/mops.js +2 -2
- package/dist/package.json +1 -1
- package/dist/tests/requirements.test.d.ts +1 -0
- package/dist/tests/requirements.test.js +46 -0
- package/dist/types.d.ts +1 -0
- package/helpers/get-lintoko-version.ts +32 -0
- package/mops.ts +2 -2
- package/package.json +1 -1
- package/tests/lint-extra-example-rules/lint/migration-self-contained/migration-self-contained.toml +1 -1
- package/tests/lint-extra-example-rules/mops.toml +1 -1
- package/tests/requirements-lintoko/mops.toml +5 -0
- package/tests/requirements.test.ts +66 -0
- package/types.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Next
|
|
4
4
|
|
|
5
|
+
## 2.16.0
|
|
6
|
+
|
|
7
|
+
- `mops bench` now compiles benchmark canisters under **enhanced orthogonal persistence** (moc's default) instead of forcing `--legacy-persistence` — measuring the persistence mode real canisters run. Pass `--legacy-persistence` to opt back into legacy persistence.
|
|
8
|
+
- `mops bench --query` measures each cell in a **query** call instead of an update call. Queries run no GC on the IC, so the instruction counts exclude GC work an update would incur — for benchmarking `query`/read-only workloads realistically. Only for synchronous benchmark runners (no inter-canister `await`).
|
|
9
|
+
- `[requirements].lintoko` declares a minimum lintoko version for package consumers. `mops install` (and `mops add`, `mops toolchain use`) warn when the project's lintoko is below a dependency's requirement, same as `moc` (#597).
|
|
10
|
+
|
|
5
11
|
## 2.15.2
|
|
6
12
|
|
|
7
13
|
- `mops check-stable` (and the stable check inside `mops check`) reports when `[canisters.<name>.migrations].check-limit` is set but more migrations are pending than the limit allows. If the compatibility check failed, the check-limit diagnostic replaces the misleading `moc` error; if it passed anyway, a warning is shown. Compares the deployed `.most` baseline against the local chain; use `--no-check-limit` to suppress.
|
package/bundle/cli.tgz
CHANGED
|
Binary file
|
package/check-requirements.ts
CHANGED
|
@@ -5,47 +5,69 @@ import chalk from "chalk";
|
|
|
5
5
|
import { getDependencyType, getRootDir, readConfig } from "./mops.js";
|
|
6
6
|
import { resolvePackages } from "./resolve-packages.js";
|
|
7
7
|
import { getMocSemVer } from "./helpers/get-moc-version.js";
|
|
8
|
+
import { getLintokoSemVer } from "./helpers/get-lintoko-version.js";
|
|
8
9
|
import { getPackageId } from "./helpers/get-package-id.js";
|
|
10
|
+
import type { Requirements } from "./types.js";
|
|
11
|
+
|
|
12
|
+
type ToolRequirement = keyof Requirements;
|
|
13
|
+
|
|
14
|
+
const TOOL_REQUIREMENTS: {
|
|
15
|
+
tool: ToolRequirement;
|
|
16
|
+
getInstalled: () => SemVer | null;
|
|
17
|
+
}[] = [
|
|
18
|
+
{ tool: "moc", getInstalled: getMocSemVer },
|
|
19
|
+
{ tool: "lintoko", getInstalled: getLintokoSemVer },
|
|
20
|
+
];
|
|
9
21
|
|
|
10
22
|
export async function checkRequirements({ verbose = false } = {}) {
|
|
11
|
-
let installedMoc = getMocSemVer();
|
|
12
|
-
if (!installedMoc) {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
let highestRequiredMoc = new SemVer("0.0.0");
|
|
16
|
-
let highestRequiredMocPkgId = "";
|
|
17
23
|
let rootDir = getRootDir();
|
|
18
|
-
|
|
19
24
|
let resolvedPackages = await resolvePackages();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
|
|
26
|
+
for (let { tool, getInstalled } of TOOL_REQUIREMENTS) {
|
|
27
|
+
let installed = getInstalled();
|
|
28
|
+
if (!installed) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let highestRequired = new SemVer("0.0.0");
|
|
33
|
+
let highestRequiredPkgId = "";
|
|
34
|
+
|
|
35
|
+
for (let [name, version] of Object.entries(resolvedPackages)) {
|
|
36
|
+
if (getDependencyType(version) === "mops") {
|
|
37
|
+
let pkgId = getPackageId(name, version);
|
|
38
|
+
let depConfig = readConfig(
|
|
39
|
+
path.join(rootDir, ".mops", pkgId, "mops.toml"),
|
|
40
|
+
);
|
|
41
|
+
let required = depConfig.requirements?.[tool];
|
|
42
|
+
|
|
43
|
+
if (required) {
|
|
44
|
+
let requiredVersion = new SemVer(required);
|
|
45
|
+
if (highestRequired.compare(requiredVersion) < 0) {
|
|
46
|
+
highestRequired = requiredVersion;
|
|
47
|
+
highestRequiredPkgId = pkgId;
|
|
48
|
+
}
|
|
49
|
+
verbose && _check(tool, pkgId, installed, requiredVersion);
|
|
33
50
|
}
|
|
34
|
-
verbose && _check(pkgId, installedMoc, requiredMoc);
|
|
35
51
|
}
|
|
36
52
|
}
|
|
37
|
-
}
|
|
38
53
|
|
|
39
|
-
|
|
54
|
+
verbose || _check(tool, highestRequiredPkgId, installed, highestRequired);
|
|
55
|
+
}
|
|
40
56
|
}
|
|
41
57
|
|
|
42
|
-
function _check(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
58
|
+
function _check(
|
|
59
|
+
tool: ToolRequirement,
|
|
60
|
+
pkgId: string,
|
|
61
|
+
installed: SemVer,
|
|
62
|
+
required: SemVer,
|
|
63
|
+
) {
|
|
64
|
+
if (!pkgId || installed.compare(required) >= 0) {
|
|
65
|
+
return;
|
|
50
66
|
}
|
|
67
|
+
|
|
68
|
+
console.log(
|
|
69
|
+
chalk.yellow(`${tool} version does not meet the requirements of ${pkgId}`),
|
|
70
|
+
);
|
|
71
|
+
console.log(chalk.yellow(` Required: >= ${required.format()}`));
|
|
72
|
+
console.log(chalk.yellow(` Installed: ${installed.format()}`));
|
|
51
73
|
}
|
package/cli.ts
CHANGED
|
@@ -558,6 +558,18 @@ program
|
|
|
558
558
|
),
|
|
559
559
|
)
|
|
560
560
|
// .addOption(new Option('--force-gc', 'Force GC'))
|
|
561
|
+
.addOption(
|
|
562
|
+
new Option(
|
|
563
|
+
"--query",
|
|
564
|
+
"Measure each cell in a query call (how `query` methods run on the IC: no GC). Only for benchmarks whose runner is synchronous (no inter-canister calls)",
|
|
565
|
+
),
|
|
566
|
+
)
|
|
567
|
+
.addOption(
|
|
568
|
+
new Option(
|
|
569
|
+
"--legacy-persistence",
|
|
570
|
+
"Compile benchmark canisters under legacy persistence instead of enhanced orthogonal persistence (the default)",
|
|
571
|
+
),
|
|
572
|
+
)
|
|
561
573
|
.addOption(
|
|
562
574
|
new Option(
|
|
563
575
|
"--verbose",
|
package/commands/bench.ts
CHANGED
|
@@ -40,6 +40,8 @@ type BenchOptions = {
|
|
|
40
40
|
compilerVersion: string;
|
|
41
41
|
gc: "copying" | "compacting" | "generational" | "incremental";
|
|
42
42
|
forceGc: boolean;
|
|
43
|
+
query: boolean;
|
|
44
|
+
legacyPersistence: boolean;
|
|
43
45
|
save: boolean;
|
|
44
46
|
compare: boolean;
|
|
45
47
|
verbose: boolean;
|
|
@@ -61,6 +63,8 @@ export async function bench(
|
|
|
61
63
|
compilerVersion: getMocVersion(true),
|
|
62
64
|
gc: "copying",
|
|
63
65
|
forceGc: true,
|
|
66
|
+
query: false,
|
|
67
|
+
legacyPersistence: false,
|
|
64
68
|
save: false,
|
|
65
69
|
compare: false,
|
|
66
70
|
verbose: false,
|
|
@@ -120,6 +124,14 @@ export async function bench(
|
|
|
120
124
|
` gc: ${options.gc}${options.forceGc ? " (forced)" : ""}`,
|
|
121
125
|
),
|
|
122
126
|
);
|
|
127
|
+
console.log(
|
|
128
|
+
chalk.gray(` context: ${options.query ? "query" : "update"}`),
|
|
129
|
+
);
|
|
130
|
+
console.log(
|
|
131
|
+
chalk.gray(
|
|
132
|
+
` persistence: ${options.legacyPersistence ? "legacy" : "enhanced"}`,
|
|
133
|
+
),
|
|
134
|
+
);
|
|
123
135
|
console.log(chalk.gray(` profile: ${options.profile}`));
|
|
124
136
|
console.log(chalk.gray(` optimize: ${optimize}`));
|
|
125
137
|
}
|
|
@@ -270,7 +282,12 @@ function computeDiffAll(
|
|
|
270
282
|
function getMocArgs(options: BenchOptions): string {
|
|
271
283
|
let args = "";
|
|
272
284
|
|
|
285
|
+
// Benchmarks compile under enhanced orthogonal persistence (moc's default
|
|
286
|
+
// since 0.15) — the mode real canisters run. Pass `--legacy-persistence`
|
|
287
|
+
// only when the user opts in, and only where moc supports the flag (>= 0.15;
|
|
288
|
+
// legacy is already the default below it).
|
|
273
289
|
if (
|
|
290
|
+
options.legacyPersistence &&
|
|
274
291
|
options.compilerVersion &&
|
|
275
292
|
new SemVer(options.compilerVersion).compare("0.15.0") >= 0
|
|
276
293
|
) {
|
|
@@ -533,13 +550,14 @@ async function runBenchFile(
|
|
|
533
550
|
log();
|
|
534
551
|
}
|
|
535
552
|
|
|
536
|
-
// run all cells
|
|
553
|
+
// run all cells. `--query` measures in query context (how `query` methods
|
|
554
|
+
// actually run on the IC: no GC), at the cost of not supporting benches whose
|
|
555
|
+
// runner performs async calls. Otherwise use the update path.
|
|
537
556
|
for (let [rowIndex, row] of schema.rows.entries()) {
|
|
538
557
|
for (let [colIndex, col] of schema.cols.entries()) {
|
|
539
|
-
let res =
|
|
540
|
-
BigInt(rowIndex),
|
|
541
|
-
BigInt(colIndex)
|
|
542
|
-
);
|
|
558
|
+
let res = options.query
|
|
559
|
+
? await actor.runCellQuery(BigInt(rowIndex), BigInt(colIndex))
|
|
560
|
+
: await actor.runCellUpdateAwait(BigInt(rowIndex), BigInt(colIndex));
|
|
543
561
|
results.set(`${row}:${col}`, res);
|
|
544
562
|
|
|
545
563
|
// @ts-ignore
|
|
@@ -337,9 +337,7 @@ async function update(tool?: Tool) {
|
|
|
337
337
|
config.toolchain[tool] = version;
|
|
338
338
|
writeConfig(config);
|
|
339
339
|
|
|
340
|
-
|
|
341
|
-
await checkRequirements();
|
|
342
|
-
}
|
|
340
|
+
await checkRequirements();
|
|
343
341
|
|
|
344
342
|
if (oldVersion === version) {
|
|
345
343
|
console.log(`Latest ${tool} ${version} is already installed`);
|
|
@@ -4,38 +4,45 @@ import chalk from "chalk";
|
|
|
4
4
|
import { getDependencyType, getRootDir, readConfig } from "./mops.js";
|
|
5
5
|
import { resolvePackages } from "./resolve-packages.js";
|
|
6
6
|
import { getMocSemVer } from "./helpers/get-moc-version.js";
|
|
7
|
+
import { getLintokoSemVer } from "./helpers/get-lintoko-version.js";
|
|
7
8
|
import { getPackageId } from "./helpers/get-package-id.js";
|
|
9
|
+
const TOOL_REQUIREMENTS = [
|
|
10
|
+
{ tool: "moc", getInstalled: getMocSemVer },
|
|
11
|
+
{ tool: "lintoko", getInstalled: getLintokoSemVer },
|
|
12
|
+
];
|
|
8
13
|
export async function checkRequirements({ verbose = false } = {}) {
|
|
9
|
-
let installedMoc = getMocSemVer();
|
|
10
|
-
if (!installedMoc) {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
let highestRequiredMoc = new SemVer("0.0.0");
|
|
14
|
-
let highestRequiredMocPkgId = "";
|
|
15
14
|
let rootDir = getRootDir();
|
|
16
15
|
let resolvedPackages = await resolvePackages();
|
|
17
|
-
for (let
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
for (let { tool, getInstalled } of TOOL_REQUIREMENTS) {
|
|
17
|
+
let installed = getInstalled();
|
|
18
|
+
if (!installed) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
let highestRequired = new SemVer("0.0.0");
|
|
22
|
+
let highestRequiredPkgId = "";
|
|
23
|
+
for (let [name, version] of Object.entries(resolvedPackages)) {
|
|
24
|
+
if (getDependencyType(version) === "mops") {
|
|
25
|
+
let pkgId = getPackageId(name, version);
|
|
26
|
+
let depConfig = readConfig(path.join(rootDir, ".mops", pkgId, "mops.toml"));
|
|
27
|
+
let required = depConfig.requirements?.[tool];
|
|
28
|
+
if (required) {
|
|
29
|
+
let requiredVersion = new SemVer(required);
|
|
30
|
+
if (highestRequired.compare(requiredVersion) < 0) {
|
|
31
|
+
highestRequired = requiredVersion;
|
|
32
|
+
highestRequiredPkgId = pkgId;
|
|
33
|
+
}
|
|
34
|
+
verbose && _check(tool, pkgId, installed, requiredVersion);
|
|
27
35
|
}
|
|
28
|
-
verbose && _check(pkgId, installedMoc, requiredMoc);
|
|
29
36
|
}
|
|
30
37
|
}
|
|
38
|
+
verbose || _check(tool, highestRequiredPkgId, installed, highestRequired);
|
|
31
39
|
}
|
|
32
|
-
verbose || _check(highestRequiredMocPkgId, installedMoc, highestRequiredMoc);
|
|
33
40
|
}
|
|
34
|
-
function _check(pkgId,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
console.log(chalk.yellow(`moc version does not meet the requirements of ${pkgId}`));
|
|
38
|
-
console.log(chalk.yellow(` Required: >= ${requiredMoc.format()}`));
|
|
39
|
-
console.log(chalk.yellow(` Installed: ${installedMoc.format()}`));
|
|
41
|
+
function _check(tool, pkgId, installed, required) {
|
|
42
|
+
if (!pkgId || installed.compare(required) >= 0) {
|
|
43
|
+
return;
|
|
40
44
|
}
|
|
45
|
+
console.log(chalk.yellow(`${tool} version does not meet the requirements of ${pkgId}`));
|
|
46
|
+
console.log(chalk.yellow(` Required: >= ${required.format()}`));
|
|
47
|
+
console.log(chalk.yellow(` Installed: ${installed.format()}`));
|
|
41
48
|
}
|
package/dist/cli.js
CHANGED
|
@@ -401,6 +401,8 @@ program
|
|
|
401
401
|
.addOption(new Option("--save", "Save benchmark results to .bench/<filename>.json"))
|
|
402
402
|
.addOption(new Option("--compare", "Run benchmark and compare results with .bench/<filename>.json"))
|
|
403
403
|
// .addOption(new Option('--force-gc', 'Force GC'))
|
|
404
|
+
.addOption(new Option("--query", "Measure each cell in a query call (how `query` methods run on the IC: no GC). Only for benchmarks whose runner is synchronous (no inter-canister calls)"))
|
|
405
|
+
.addOption(new Option("--legacy-persistence", "Compile benchmark canisters under legacy persistence instead of enhanced orthogonal persistence (the default)"))
|
|
404
406
|
.addOption(new Option("--verbose", "Print the benchmark pipeline (compiler, replica, GC, optimization) and stream compiler/replica output, including dfx optimization warnings"))
|
|
405
407
|
.action(async (filter, options) => {
|
|
406
408
|
checkConfigFile(true);
|
package/dist/commands/bench.d.ts
CHANGED
package/dist/commands/bench.js
CHANGED
|
@@ -31,6 +31,8 @@ export async function bench(filter = "", optionsArg = {}) {
|
|
|
31
31
|
compilerVersion: getMocVersion(true),
|
|
32
32
|
gc: "copying",
|
|
33
33
|
forceGc: true,
|
|
34
|
+
query: false,
|
|
35
|
+
legacyPersistence: false,
|
|
34
36
|
save: false,
|
|
35
37
|
compare: false,
|
|
36
38
|
verbose: false,
|
|
@@ -71,6 +73,8 @@ export async function bench(filter = "", optionsArg = {}) {
|
|
|
71
73
|
console.log(chalk.gray(` compiler: moc ${options.compilerVersion}`));
|
|
72
74
|
console.log(chalk.gray(` replica: ${replicaType}${options.replicaVersion ? ` ${options.replicaVersion}` : ""}`));
|
|
73
75
|
console.log(chalk.gray(` gc: ${options.gc}${options.forceGc ? " (forced)" : ""}`));
|
|
76
|
+
console.log(chalk.gray(` context: ${options.query ? "query" : "update"}`));
|
|
77
|
+
console.log(chalk.gray(` persistence: ${options.legacyPersistence ? "legacy" : "enhanced"}`));
|
|
74
78
|
console.log(chalk.gray(` profile: ${options.profile}`));
|
|
75
79
|
console.log(chalk.gray(` optimize: ${optimize}`));
|
|
76
80
|
}
|
|
@@ -188,7 +192,12 @@ function computeDiffAll(currentResults, prevResults, rows, cols) {
|
|
|
188
192
|
}
|
|
189
193
|
function getMocArgs(options) {
|
|
190
194
|
let args = "";
|
|
191
|
-
|
|
195
|
+
// Benchmarks compile under enhanced orthogonal persistence (moc's default
|
|
196
|
+
// since 0.15) — the mode real canisters run. Pass `--legacy-persistence`
|
|
197
|
+
// only when the user opts in, and only where moc supports the flag (>= 0.15;
|
|
198
|
+
// legacy is already the default below it).
|
|
199
|
+
if (options.legacyPersistence &&
|
|
200
|
+
options.compilerVersion &&
|
|
192
201
|
new SemVer(options.compilerVersion).compare("0.15.0") >= 0) {
|
|
193
202
|
args += " --legacy-persistence";
|
|
194
203
|
}
|
|
@@ -386,10 +395,14 @@ async function runBenchFile(file, options, replica) {
|
|
|
386
395
|
if (canUpdateLog) {
|
|
387
396
|
log();
|
|
388
397
|
}
|
|
389
|
-
// run all cells
|
|
398
|
+
// run all cells. `--query` measures in query context (how `query` methods
|
|
399
|
+
// actually run on the IC: no GC), at the cost of not supporting benches whose
|
|
400
|
+
// runner performs async calls. Otherwise use the update path.
|
|
390
401
|
for (let [rowIndex, row] of schema.rows.entries()) {
|
|
391
402
|
for (let [colIndex, col] of schema.cols.entries()) {
|
|
392
|
-
let res =
|
|
403
|
+
let res = options.query
|
|
404
|
+
? await actor.runCellQuery(BigInt(rowIndex), BigInt(colIndex))
|
|
405
|
+
: await actor.runCellUpdateAwait(BigInt(rowIndex), BigInt(colIndex));
|
|
393
406
|
results.set(`${row}:${col}`, res);
|
|
394
407
|
// @ts-ignore
|
|
395
408
|
instructionsCells[rowIndex][colIndex] = res.instructions;
|
|
@@ -259,9 +259,7 @@ async function update(tool) {
|
|
|
259
259
|
let oldVersion = config.toolchain[tool];
|
|
260
260
|
config.toolchain[tool] = version;
|
|
261
261
|
writeConfig(config);
|
|
262
|
-
|
|
263
|
-
await checkRequirements();
|
|
264
|
-
}
|
|
262
|
+
await checkRequirements();
|
|
265
263
|
if (oldVersion === version) {
|
|
266
264
|
console.log(`Latest ${tool} ${version} is already installed`);
|
|
267
265
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { parse } from "semver";
|
|
3
|
+
import { FILE_PATH_REGEX } from "../constants.js";
|
|
4
|
+
import { readConfig } from "../mops.js";
|
|
5
|
+
export function getLintokoSemVer() {
|
|
6
|
+
return parse(getLintokoVersion(false));
|
|
7
|
+
}
|
|
8
|
+
export function getLintokoVersion(throwOnError = false) {
|
|
9
|
+
let configVersion = readConfig().toolchain?.lintoko;
|
|
10
|
+
if (!configVersion) {
|
|
11
|
+
return "";
|
|
12
|
+
}
|
|
13
|
+
if (!configVersion.match(FILE_PATH_REGEX)) {
|
|
14
|
+
return configVersion;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
let match = execFileSync(configVersion, ["--version"])
|
|
18
|
+
.toString()
|
|
19
|
+
.trim()
|
|
20
|
+
.match(/lintoko ([^\s]+)/);
|
|
21
|
+
return match?.[1] || "";
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
if (throwOnError) {
|
|
25
|
+
console.error(e);
|
|
26
|
+
throw new Error("lintoko not found");
|
|
27
|
+
}
|
|
28
|
+
return "";
|
|
29
|
+
}
|
|
30
|
+
}
|
package/dist/mops.js
CHANGED
|
@@ -177,9 +177,9 @@ export function readConfig(configFile = getClosestConfigFile()) {
|
|
|
177
177
|
processDeps(toml["dev-dependencies"] || {});
|
|
178
178
|
let config = { ...toml };
|
|
179
179
|
Object.entries(config.requirements || {}).forEach(([name, value]) => {
|
|
180
|
-
if (name === "moc") {
|
|
180
|
+
if (name === "moc" || name === "lintoko") {
|
|
181
181
|
config.requirements = config.requirements || {};
|
|
182
|
-
config.requirements
|
|
182
|
+
config.requirements[name] = value;
|
|
183
183
|
}
|
|
184
184
|
});
|
|
185
185
|
return config;
|
package/dist/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, expect, test, beforeEach, afterEach } from "@jest/globals";
|
|
2
|
+
import { cp, mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { bytesToHex } from "@noble/hashes/utils";
|
|
5
|
+
import { sha256 } from "@noble/hashes/sha256";
|
|
6
|
+
import { cli } from "./helpers";
|
|
7
|
+
describe("requirements", () => {
|
|
8
|
+
const fixtureDir = path.join(import.meta.dirname, "requirements-lintoko");
|
|
9
|
+
let tempDir;
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
tempDir = path.join(import.meta.dirname, `_tmp_requirements_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`);
|
|
12
|
+
await cp(fixtureDir, tempDir, { recursive: true });
|
|
13
|
+
const depDir = path.join(tempDir, ".mops", "my-pkg@0.1.0");
|
|
14
|
+
await mkdir(depDir, { recursive: true });
|
|
15
|
+
await writeFile(path.join(depDir, "mops.toml"), `[package]
|
|
16
|
+
name = "my-pkg"
|
|
17
|
+
version = "0.1.0"
|
|
18
|
+
|
|
19
|
+
[requirements]
|
|
20
|
+
lintoko = "0.10.0"
|
|
21
|
+
`);
|
|
22
|
+
const mopsTomlDepsHash = bytesToHex(sha256(JSON.stringify({ "my-pkg": "0.1.0" })));
|
|
23
|
+
await writeFile(path.join(tempDir, "mops.lock"), JSON.stringify({
|
|
24
|
+
version: 3,
|
|
25
|
+
mopsTomlDepsHash,
|
|
26
|
+
deps: { "my-pkg": "0.1.0" },
|
|
27
|
+
hashes: {
|
|
28
|
+
"my-pkg@0.1.0": {
|
|
29
|
+
"mops.toml": "0000000000000000000000000000000000000000000000000000000000000000",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
}));
|
|
33
|
+
});
|
|
34
|
+
afterEach(async () => {
|
|
35
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
36
|
+
});
|
|
37
|
+
test("lintoko requirement warns when installed version is too old", async () => {
|
|
38
|
+
const result = await cli(["toolchain", "use", "lintoko", "0.7.0"], {
|
|
39
|
+
cwd: tempDir,
|
|
40
|
+
});
|
|
41
|
+
expect(result.exitCode).toBe(0);
|
|
42
|
+
expect(result.stdout).toMatch(/lintoko version does not meet the requirements of my-pkg@0\.1\.0/);
|
|
43
|
+
expect(result.stdout).toMatch(/Required: >= 0\.10\.0/);
|
|
44
|
+
expect(result.stdout).toMatch(/Installed:\s+0\.7\.0/);
|
|
45
|
+
});
|
|
46
|
+
});
|
package/dist/types.d.ts
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { type SemVer, parse } from "semver";
|
|
3
|
+
import { FILE_PATH_REGEX } from "../constants.js";
|
|
4
|
+
import { readConfig } from "../mops.js";
|
|
5
|
+
|
|
6
|
+
export function getLintokoSemVer(): SemVer | null {
|
|
7
|
+
return parse(getLintokoVersion(false));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getLintokoVersion(throwOnError = false): string {
|
|
11
|
+
let configVersion = readConfig().toolchain?.lintoko;
|
|
12
|
+
if (!configVersion) {
|
|
13
|
+
return "";
|
|
14
|
+
}
|
|
15
|
+
if (!configVersion.match(FILE_PATH_REGEX)) {
|
|
16
|
+
return configVersion;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
let match = execFileSync(configVersion, ["--version"])
|
|
21
|
+
.toString()
|
|
22
|
+
.trim()
|
|
23
|
+
.match(/lintoko ([^\s]+)/);
|
|
24
|
+
return match?.[1] || "";
|
|
25
|
+
} catch (e) {
|
|
26
|
+
if (throwOnError) {
|
|
27
|
+
console.error(e);
|
|
28
|
+
throw new Error("lintoko not found");
|
|
29
|
+
}
|
|
30
|
+
return "";
|
|
31
|
+
}
|
|
32
|
+
}
|
package/mops.ts
CHANGED
|
@@ -205,9 +205,9 @@ export function readConfig(configFile = getClosestConfigFile()): Config {
|
|
|
205
205
|
let config: Config = { ...toml };
|
|
206
206
|
|
|
207
207
|
Object.entries(config.requirements || {}).forEach(([name, value]) => {
|
|
208
|
-
if (name === "moc") {
|
|
208
|
+
if (name === "moc" || name === "lintoko") {
|
|
209
209
|
config.requirements = config.requirements || {};
|
|
210
|
-
config.requirements
|
|
210
|
+
config.requirements[name] = value;
|
|
211
211
|
}
|
|
212
212
|
});
|
|
213
213
|
|
package/package.json
CHANGED
package/tests/lint-extra-example-rules/lint/migration-self-contained/migration-self-contained.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
name = "migration-self-contained"
|
|
2
2
|
description = "Migration files must not import local modules (relative paths). Got: @path"
|
|
3
|
-
includes = ["
|
|
3
|
+
includes = ["migrations/*.mo"]
|
|
4
4
|
query = '''
|
|
5
5
|
(import (text_literal) @path @error
|
|
6
6
|
(#match? @path "^\"[^:]*\"$"))
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, expect, test, beforeEach, afterEach } from "@jest/globals";
|
|
2
|
+
import { cp, mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { bytesToHex } from "@noble/hashes/utils";
|
|
5
|
+
import { sha256 } from "@noble/hashes/sha256";
|
|
6
|
+
import { cli } from "./helpers";
|
|
7
|
+
|
|
8
|
+
describe("requirements", () => {
|
|
9
|
+
const fixtureDir = path.join(import.meta.dirname, "requirements-lintoko");
|
|
10
|
+
let tempDir: string;
|
|
11
|
+
|
|
12
|
+
beforeEach(async () => {
|
|
13
|
+
tempDir = path.join(
|
|
14
|
+
import.meta.dirname,
|
|
15
|
+
`_tmp_requirements_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
16
|
+
);
|
|
17
|
+
await cp(fixtureDir, tempDir, { recursive: true });
|
|
18
|
+
|
|
19
|
+
const depDir = path.join(tempDir, ".mops", "my-pkg@0.1.0");
|
|
20
|
+
await mkdir(depDir, { recursive: true });
|
|
21
|
+
await writeFile(
|
|
22
|
+
path.join(depDir, "mops.toml"),
|
|
23
|
+
`[package]
|
|
24
|
+
name = "my-pkg"
|
|
25
|
+
version = "0.1.0"
|
|
26
|
+
|
|
27
|
+
[requirements]
|
|
28
|
+
lintoko = "0.10.0"
|
|
29
|
+
`,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const mopsTomlDepsHash = bytesToHex(
|
|
33
|
+
sha256(JSON.stringify({ "my-pkg": "0.1.0" })),
|
|
34
|
+
);
|
|
35
|
+
await writeFile(
|
|
36
|
+
path.join(tempDir, "mops.lock"),
|
|
37
|
+
JSON.stringify({
|
|
38
|
+
version: 3,
|
|
39
|
+
mopsTomlDepsHash,
|
|
40
|
+
deps: { "my-pkg": "0.1.0" },
|
|
41
|
+
hashes: {
|
|
42
|
+
"my-pkg@0.1.0": {
|
|
43
|
+
"mops.toml":
|
|
44
|
+
"0000000000000000000000000000000000000000000000000000000000000000",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
afterEach(async () => {
|
|
52
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("lintoko requirement warns when installed version is too old", async () => {
|
|
56
|
+
const result = await cli(["toolchain", "use", "lintoko", "0.7.0"], {
|
|
57
|
+
cwd: tempDir,
|
|
58
|
+
});
|
|
59
|
+
expect(result.exitCode).toBe(0);
|
|
60
|
+
expect(result.stdout).toMatch(
|
|
61
|
+
/lintoko version does not meet the requirements of my-pkg@0\.1\.0/,
|
|
62
|
+
);
|
|
63
|
+
expect(result.stdout).toMatch(/Required: >= 0\.10\.0/);
|
|
64
|
+
expect(result.stdout).toMatch(/Installed:\s+0\.7\.0/);
|
|
65
|
+
});
|
|
66
|
+
});
|