no-mistakes 0.52.2 → 0.53.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/bin/no-mistakes.js +74 -0
- package/package.json +3 -2
- package/planning-impact-cli.js +81 -0
- package/resolve-config-types.d.ts +2 -0
package/README.md
CHANGED
|
@@ -15,8 +15,13 @@ npx no-mistakes dependents src/utils.mts --json
|
|
|
15
15
|
npx no-mistakes symbols src/utils.mts --json
|
|
16
16
|
npx no-mistakes import-usages --root . --filter 'src/**' --json
|
|
17
17
|
npx no-mistakes check --json
|
|
18
|
+
npx no-mistakes planning-impact --changed-files /private/run/changed-files.txt --output-dir /private/run
|
|
18
19
|
```
|
|
19
20
|
|
|
21
|
+
`planning-impact` is supplied by the npm package, not the Cargo-installed
|
|
22
|
+
binary. It writes the private four-report artifact contract from one prepared
|
|
23
|
+
analysis. See the [CLI reference](../../docs/cli/planning-impact.md).
|
|
24
|
+
|
|
20
25
|
Programmatic Node usage loads the same Rust analysis through N-API:
|
|
21
26
|
|
|
22
27
|
```js
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { spawn } = require("node:child_process");
|
|
5
|
+
const { join } = require("node:path");
|
|
6
|
+
const { boundedDiagnostic } = require("../planning-impact-cli");
|
|
7
|
+
|
|
8
|
+
const VALUE_OPTIONS = new Set(["--timeout", "--lock-timeout", "--jobs", "--profile", "-j"]);
|
|
9
|
+
const FLAG_OPTIONS = new Set(["--fail-on-lock"]);
|
|
10
|
+
const INLINE_VALUE_OPTION = /^(?:--(?:timeout|lock-timeout|jobs|profile)=|-j)/u;
|
|
11
|
+
|
|
12
|
+
function firstSubcommand(argv) {
|
|
13
|
+
const index = firstSubcommandIndex(argv);
|
|
14
|
+
return index === undefined ? undefined : argv[index];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function firstSubcommandIndex(argv) {
|
|
18
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
19
|
+
const value = argv[index];
|
|
20
|
+
if (value === "--") return undefined;
|
|
21
|
+
if (VALUE_OPTIONS.has(value)) {
|
|
22
|
+
index += 1;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (FLAG_OPTIONS.has(value) || INLINE_VALUE_OPTION.test(value)) {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
return index;
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function planningImpactArgs(argv) {
|
|
34
|
+
const index = firstSubcommandIndex(argv);
|
|
35
|
+
return [...argv.slice(0, index), ...argv.slice(index + 1)];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function launchNative(argv, spawnFn = spawn, io = process, kill = process.kill) {
|
|
39
|
+
const child = spawnFn(join(__dirname, "no-mistakes"), argv, { stdio: "inherit" });
|
|
40
|
+
child.on("error", (error) => {
|
|
41
|
+
io.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
42
|
+
io.exitCode = 1;
|
|
43
|
+
});
|
|
44
|
+
child.on("exit", (code, signal) => {
|
|
45
|
+
if (signal) kill(process.pid, signal);
|
|
46
|
+
else io.exitCode = code === null ? 1 : code;
|
|
47
|
+
});
|
|
48
|
+
return child;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function main(
|
|
52
|
+
argv = process.argv.slice(2),
|
|
53
|
+
{
|
|
54
|
+
io = process,
|
|
55
|
+
launchNativeFn = launchNative,
|
|
56
|
+
runPlanning = (args, planningIo) =>
|
|
57
|
+
require("../planning-impact-cli").main(args, process.cwd(), planningIo),
|
|
58
|
+
} = {},
|
|
59
|
+
) {
|
|
60
|
+
if (firstSubcommand(argv) === "planning-impact") {
|
|
61
|
+
try {
|
|
62
|
+
await runPlanning(planningImpactArgs(argv), io);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
io.stderr.write(boundedDiagnostic(error));
|
|
65
|
+
io.exitCode = 1;
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
launchNativeFn(argv);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (require.main === module) void main();
|
|
73
|
+
|
|
74
|
+
module.exports = { firstSubcommand, launchNative, main, planningImpactArgs };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "no-mistakes",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.1",
|
|
4
4
|
"description": "Static codebase analysis tools for TS/JS dependencies, dependents, and symbols",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"directory": "packages/no-mistakes"
|
|
10
10
|
},
|
|
11
11
|
"bin": {
|
|
12
|
-
"no-mistakes": "bin/no-mistakes"
|
|
12
|
+
"no-mistakes": "bin/no-mistakes.js"
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
15
|
"bin/",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"planning-impact-artifacts-inputs.js",
|
|
23
23
|
"planning-impact-artifacts-lock.js",
|
|
24
24
|
"planning-impact-artifacts-privacy.js",
|
|
25
|
+
"planning-impact-cli.js",
|
|
25
26
|
"planning.js",
|
|
26
27
|
"workflow-topology-index.js",
|
|
27
28
|
"workflow-topology-index-helpers.js",
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { parseArgs } = require("node:util");
|
|
4
|
+
|
|
5
|
+
const USAGE = [
|
|
6
|
+
"usage: no-mistakes planning-impact --changed-files <manifest>",
|
|
7
|
+
"--output-dir <directory> [--broad]",
|
|
8
|
+
].join(" ");
|
|
9
|
+
|
|
10
|
+
function parseNonNegativeInteger(name, value) {
|
|
11
|
+
if (!/^(?:0|[1-9][0-9]*)$/u.test(value)) {
|
|
12
|
+
throw new Error(`${name} must be a non-negative integer`);
|
|
13
|
+
}
|
|
14
|
+
const parsed = Number(value);
|
|
15
|
+
if (!Number.isSafeInteger(parsed)) throw new Error(`${name} must be a safe integer`);
|
|
16
|
+
return parsed;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function parsePlanningImpactArgs(argv, root) {
|
|
20
|
+
const { values } = parseArgs({
|
|
21
|
+
args: argv,
|
|
22
|
+
options: {
|
|
23
|
+
"changed-files": { type: "string" },
|
|
24
|
+
"output-dir": { type: "string" },
|
|
25
|
+
broad: { type: "boolean" },
|
|
26
|
+
timeout: { type: "string" },
|
|
27
|
+
"lock-timeout": { type: "string" },
|
|
28
|
+
"fail-on-lock": { type: "boolean" },
|
|
29
|
+
jobs: { type: "string", short: "j" },
|
|
30
|
+
profile: { type: "string" },
|
|
31
|
+
help: { type: "boolean", short: "h" },
|
|
32
|
+
},
|
|
33
|
+
strict: true,
|
|
34
|
+
});
|
|
35
|
+
if (values.help) return null;
|
|
36
|
+
if (!values["changed-files"] || !values["output-dir"]) throw new Error(USAGE);
|
|
37
|
+
if (values.profile !== undefined && values.profile !== "ci") {
|
|
38
|
+
throw new Error('profile must be "ci" when set');
|
|
39
|
+
}
|
|
40
|
+
const options = {
|
|
41
|
+
root,
|
|
42
|
+
changedFilesManifest: values["changed-files"],
|
|
43
|
+
outputDirectory: values["output-dir"],
|
|
44
|
+
broad: values.broad === true,
|
|
45
|
+
};
|
|
46
|
+
for (const [flag, key] of [
|
|
47
|
+
["timeout", "timeout"],
|
|
48
|
+
["lock-timeout", "lockTimeout"],
|
|
49
|
+
["jobs", "jobs"],
|
|
50
|
+
]) {
|
|
51
|
+
if (values[flag] !== undefined) options[key] = parseNonNegativeInteger(flag, values[flag]);
|
|
52
|
+
}
|
|
53
|
+
if (values["fail-on-lock"]) options.failOnLock = true;
|
|
54
|
+
if (values.profile) options.profile = values.profile;
|
|
55
|
+
return options;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function runPlanningImpact(argv, root, writer) {
|
|
59
|
+
const options = parsePlanningImpactArgs(argv, root);
|
|
60
|
+
if (options) await writer(options);
|
|
61
|
+
return options;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function boundedDiagnostic(error) {
|
|
65
|
+
const detail = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
66
|
+
return Buffer.from(`${detail}\n`)
|
|
67
|
+
.subarray(0, 4096)
|
|
68
|
+
.toString("utf8")
|
|
69
|
+
.replace(/\ufffd+$/u, "");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function main(argv = process.argv.slice(2), root = process.cwd(), io = process, writer) {
|
|
73
|
+
const options = parsePlanningImpactArgs(argv, root);
|
|
74
|
+
if (!options) {
|
|
75
|
+
io.stdout.write(`${USAGE}\n`);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
await (writer || require("./index").writePlanningImpactArtifacts)(options);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = { USAGE, boundedDiagnostic, main, parsePlanningImpactArgs, runPlanningImpact };
|
|
@@ -41,6 +41,8 @@ export interface ResolvedTrigger {
|
|
|
41
41
|
name: string;
|
|
42
42
|
paths: string[];
|
|
43
43
|
targets: string[];
|
|
44
|
+
/** Effective changed-test expansion policy; present only for structured triggers. */
|
|
45
|
+
includeChangedTests?: boolean;
|
|
44
46
|
source: "triggers" | "projects";
|
|
45
47
|
}
|
|
46
48
|
|