no-mistakes 0.58.0 → 0.60.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/README.md +8 -2
- package/index.js +3 -48
- package/package.json +5 -6
- package/planning.js +26 -1
- package/scripts/native-package.js +0 -1
package/README.md
CHANGED
|
@@ -9,8 +9,10 @@ The async N-API facade avoids subprocess parsing and reuses one prepared
|
|
|
9
9
|
analysis for related reports.
|
|
10
10
|
|
|
11
11
|
Published installs select a platform-specific optional package containing both
|
|
12
|
-
the CLI and N-API addon.
|
|
13
|
-
|
|
12
|
+
the CLI and N-API addon. Prebuilt packages support macOS ARM64, Linux ARM64 and
|
|
13
|
+
x64 with glibc, and Windows x64; Intel Macs are not supported. Repository
|
|
14
|
+
contributors build and stage the local native package explicitly with
|
|
15
|
+
`pnpm run build:native` before running the CLI.
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
18
|
npm install --save-dev no-mistakes
|
|
@@ -48,6 +50,10 @@ const report = await analyzeProject({
|
|
|
48
50
|
Use `analyzeProject()` when reports share a root and configuration. Dedicated
|
|
49
51
|
functions remain convenient for a single query:
|
|
50
52
|
|
|
53
|
+
`testsWhy` reports that receive `planJson` are materialized in a private
|
|
54
|
+
temporary directory and cleaned up after success, native rejection, or
|
|
55
|
+
preparation failure, including when they are batched through `analyzeProject()`.
|
|
56
|
+
|
|
51
57
|
````js
|
|
52
58
|
const {
|
|
53
59
|
dependencies,
|
package/index.js
CHANGED
|
@@ -7,7 +7,6 @@ const planning = require("./planning");
|
|
|
7
7
|
const { writePlanningImpactArtifacts: writeArtifacts } = require("./planning-impact-artifacts");
|
|
8
8
|
const { createPlanningArtifactLock } = require("./planning-impact-artifacts-lock");
|
|
9
9
|
const { createWorkflowTopologyIndex } = require("./workflow-topology-index");
|
|
10
|
-
const fs = require("node:fs");
|
|
11
10
|
const path = require("node:path");
|
|
12
11
|
|
|
13
12
|
async function callJson(fn, options) {
|
|
@@ -64,7 +63,6 @@ const jsonApis = createJsonApis({
|
|
|
64
63
|
symbols: "symbolsJson",
|
|
65
64
|
});
|
|
66
65
|
|
|
67
|
-
const PLAN_INPUT_REPORTS = new Set(["testsComment", "testsGraph", "testsGraphMermaid"]);
|
|
68
66
|
const CAMELIZE_REPORTS = new Set(["testsPlan", "testsImpact", "testsTargets", "testsGraph"]);
|
|
69
67
|
const acquirePlanningArtifactLock = createPlanningArtifactLock(native);
|
|
70
68
|
|
|
@@ -73,18 +71,7 @@ async function analyzeProject(options = {}) {
|
|
|
73
71
|
const generatedDirs = [];
|
|
74
72
|
try {
|
|
75
73
|
if (Array.isArray(request.reports)) {
|
|
76
|
-
request.reports = await
|
|
77
|
-
request.reports.map(async (report) => {
|
|
78
|
-
if (report.type === "testsWhy") {
|
|
79
|
-
const prepared = await planning.prepareWhyPlan(report);
|
|
80
|
-
if (prepared.generatedDir) generatedDirs.push(prepared.generatedDir);
|
|
81
|
-
return prepared.request;
|
|
82
|
-
}
|
|
83
|
-
return PLAN_INPUT_REPORTS.has(report.type)
|
|
84
|
-
? await planning.decamelizePlanOptions(report)
|
|
85
|
-
: report;
|
|
86
|
-
}),
|
|
87
|
-
);
|
|
74
|
+
request.reports = await planning.prepareAnalyzeProjectReports(request.reports, generatedDirs);
|
|
88
75
|
}
|
|
89
76
|
const result = await jsonApis.analyzeProject(request);
|
|
90
77
|
for (const report of result.reports || []) {
|
|
@@ -114,40 +101,8 @@ async function writePlanningImpactArtifacts(options) {
|
|
|
114
101
|
);
|
|
115
102
|
}
|
|
116
103
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
async function ciTopology(options) {
|
|
120
|
-
const root = path.resolve((options && options.root) || process.cwd());
|
|
121
|
-
const configPath = path.resolve(root, (options && options.config) || ".no-mistakes.yml");
|
|
122
|
-
let mtime = 0;
|
|
123
|
-
try {
|
|
124
|
-
mtime = fs.statSync(configPath).mtimeMs;
|
|
125
|
-
} catch {
|
|
126
|
-
mtime = 0;
|
|
127
|
-
}
|
|
128
|
-
const workflows = JSON.stringify(
|
|
129
|
-
[]
|
|
130
|
-
.concat((options && options.workflows) || [])
|
|
131
|
-
.map(String)
|
|
132
|
-
.sort(),
|
|
133
|
-
);
|
|
134
|
-
const identity = `${root}\0${configPath}\0`;
|
|
135
|
-
const key = `${identity}${mtime}\0${workflows}`;
|
|
136
|
-
const stale = [];
|
|
137
|
-
for (const memoKey of topologyMemo.keys()) {
|
|
138
|
-
if (!memoKey.startsWith(identity)) continue;
|
|
139
|
-
const memoMtime = memoKey.slice(identity.length).split("\0")[0];
|
|
140
|
-
if (memoMtime !== String(mtime)) stale.push(memoKey);
|
|
141
|
-
}
|
|
142
|
-
for (const memoKey of stale) topologyMemo.delete(memoKey);
|
|
143
|
-
const cached = topologyMemo.get(key);
|
|
144
|
-
if (cached) return cached.then((value) => structuredClone(value));
|
|
145
|
-
const pending = jsonApis.ciTopology({ ...options, root }).catch((error) => {
|
|
146
|
-
topologyMemo.delete(key);
|
|
147
|
-
throw error;
|
|
148
|
-
});
|
|
149
|
-
topologyMemo.set(key, pending);
|
|
150
|
-
return pending.then((value) => structuredClone(value));
|
|
104
|
+
async function ciTopology(options = {}) {
|
|
105
|
+
return jsonApis.ciTopology({ ...options, root: path.resolve(options.root || process.cwd()) });
|
|
151
106
|
}
|
|
152
107
|
|
|
153
108
|
const version = () => native.version();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "no-mistakes",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.60.0",
|
|
4
4
|
"description": "Deterministic impact maps, test plans, Playwright coverage, and repository checks for coding agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -45,10 +45,9 @@
|
|
|
45
45
|
"access": "public"
|
|
46
46
|
},
|
|
47
47
|
"optionalDependencies": {
|
|
48
|
-
"no-mistakes-darwin-arm64": "0.
|
|
49
|
-
"no-mistakes-
|
|
50
|
-
"no-mistakes-linux-
|
|
51
|
-
"no-mistakes-
|
|
52
|
-
"no-mistakes-win32-x64-msvc": "0.58.0"
|
|
48
|
+
"no-mistakes-darwin-arm64": "0.60.0",
|
|
49
|
+
"no-mistakes-linux-arm64-gnu": "0.60.0",
|
|
50
|
+
"no-mistakes-linux-x64-gnu": "0.60.0",
|
|
51
|
+
"no-mistakes-win32-x64-msvc": "0.60.0"
|
|
53
52
|
}
|
|
54
53
|
}
|
package/planning.js
CHANGED
|
@@ -7,6 +7,7 @@ const { resolveNativePackage } = require("./scripts/native-package");
|
|
|
7
7
|
const native = require(
|
|
8
8
|
process.env.NO_MISTAKES_TEST_NAPI_ADDON_PATH || resolveNativePackage().addonPath,
|
|
9
9
|
);
|
|
10
|
+
const PLAN_INPUT_REPORTS = new Set(["testsComment", "testsGraph", "testsGraphMermaid"]);
|
|
10
11
|
|
|
11
12
|
async function callJson(fn, options) {
|
|
12
13
|
const input = Buffer.from(JSON.stringify(options || {}));
|
|
@@ -94,7 +95,15 @@ async function prepareWhyPlan(options = {}) {
|
|
|
94
95
|
}
|
|
95
96
|
if (document == null) return { request: next };
|
|
96
97
|
const generatedDir = await fs.mkdtemp(path.join(os.tmpdir(), "no-mistakes-why-"));
|
|
97
|
-
|
|
98
|
+
try {
|
|
99
|
+
await fs.writeFile(
|
|
100
|
+
path.join(generatedDir, "plan.json"),
|
|
101
|
+
JSON.stringify(loadPlanJson(document)),
|
|
102
|
+
);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
await removeGeneratedDir(generatedDir);
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
98
107
|
next.plan = path.join(generatedDir, "plan.json");
|
|
99
108
|
delete next.planJson;
|
|
100
109
|
return { request: next, generatedDir };
|
|
@@ -109,6 +118,21 @@ async function removeGeneratedDir(generatedDir) {
|
|
|
109
118
|
await fs.rm(generatedDir, { recursive: true, force: true }).catch(() => {});
|
|
110
119
|
}
|
|
111
120
|
|
|
121
|
+
async function prepareAnalyzeProjectReports(reports, generatedDirs) {
|
|
122
|
+
const preparations = reports.map(async (report) => {
|
|
123
|
+
if (report.type === "testsWhy") {
|
|
124
|
+
const prepared = await prepareWhyPlan(report);
|
|
125
|
+
if (prepared.generatedDir) generatedDirs.push(prepared.generatedDir);
|
|
126
|
+
return prepared.request;
|
|
127
|
+
}
|
|
128
|
+
return PLAN_INPUT_REPORTS.has(report.type) ? await decamelizePlanOptions(report) : report;
|
|
129
|
+
});
|
|
130
|
+
const settled = await Promise.allSettled(preparations);
|
|
131
|
+
const rejected = settled.find((result) => result.status === "rejected");
|
|
132
|
+
if (rejected) throw rejected.reason;
|
|
133
|
+
return settled.map((result) => result.value);
|
|
134
|
+
}
|
|
135
|
+
|
|
112
136
|
function camelizeWhy(value) {
|
|
113
137
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
114
138
|
return camelizeValue(value);
|
|
@@ -176,6 +200,7 @@ module.exports = {
|
|
|
176
200
|
camelizeWhy,
|
|
177
201
|
decamelizePlanOptions,
|
|
178
202
|
materializeWhyPlan,
|
|
203
|
+
prepareAnalyzeProjectReports,
|
|
179
204
|
prepareWhyPlan,
|
|
180
205
|
removeGeneratedDir,
|
|
181
206
|
testsComment,
|
|
@@ -7,7 +7,6 @@ const MIN_GLIBC = [2, 35];
|
|
|
7
7
|
|
|
8
8
|
const PACKAGE_NAMES = new Map([
|
|
9
9
|
["darwin/arm64", "no-mistakes-darwin-arm64"],
|
|
10
|
-
["darwin/x64", "no-mistakes-darwin-x64"],
|
|
11
10
|
["linux/arm64", "no-mistakes-linux-arm64-gnu"],
|
|
12
11
|
["linux/x64", "no-mistakes-linux-x64-gnu"],
|
|
13
12
|
["win32/x64", "no-mistakes-win32-x64-msvc"],
|