pi-usereq 0.44.0 → 0.46.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 +24 -0
- package/README.md +1 -1
- package/package.json +10 -2
- package/pi-usereq/docs/REFERENCES.md +95 -53
- package/pi-usereq/docs/REQUIREMENTS.md +20 -5
- package/pi-usereq/docs/WORKFLOW.md +16 -6
- package/scripts/install-static-checkers.ts +196 -2
- package/src/core/static-check.ts +13 -7
- package/src/index.ts +200 -4
- package/tests/extension-registration.test.ts +9 -2
- package/tests/static-check-bundled.test.ts +207 -1
|
@@ -17,7 +17,17 @@ import {
|
|
|
17
17
|
} from "../src/core/static-check.js";
|
|
18
18
|
import { getInstallationPath } from "../src/core/path-context.js";
|
|
19
19
|
import { getDefaultConfig } from "../src/core/config.js";
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
main as installStaticCheckersMain,
|
|
22
|
+
approvePendingInstallScripts,
|
|
23
|
+
getConsumerInstallRoot,
|
|
24
|
+
selectInstallScriptPackageNames,
|
|
25
|
+
mergeAllowScriptsEntries,
|
|
26
|
+
} from "../scripts/install-static-checkers.ts";
|
|
27
|
+
import type {
|
|
28
|
+
NodeModulesPackage,
|
|
29
|
+
InstallScriptApprovalDeps,
|
|
30
|
+
} from "../scripts/install-static-checkers.ts";
|
|
21
31
|
|
|
22
32
|
const require = createRequire(import.meta.url);
|
|
23
33
|
const ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..");
|
|
@@ -98,3 +108,199 @@ test("checkDefaultCheckersAvailability returns empty array when all checkers dis
|
|
|
98
108
|
const missing = checkDefaultCheckersAvailability(config);
|
|
99
109
|
assert.equal(missing.length, 0);
|
|
100
110
|
});
|
|
111
|
+
|
|
112
|
+
test("getConsumerInstallRoot resolves INIT_CWD as the consumer install root", () => {
|
|
113
|
+
const previousInitCwd = process.env.INIT_CWD;
|
|
114
|
+
const previousPrefix = process.env.npm_config_local_prefix;
|
|
115
|
+
try {
|
|
116
|
+
process.env.INIT_CWD = "/tmp/pi-usereq-consumer-root";
|
|
117
|
+
delete process.env.npm_config_local_prefix;
|
|
118
|
+
assert.equal(getConsumerInstallRoot(), "/tmp/pi-usereq-consumer-root");
|
|
119
|
+
} finally {
|
|
120
|
+
if (previousInitCwd === undefined) {
|
|
121
|
+
delete process.env.INIT_CWD;
|
|
122
|
+
} else {
|
|
123
|
+
process.env.INIT_CWD = previousInitCwd;
|
|
124
|
+
}
|
|
125
|
+
if (previousPrefix === undefined) {
|
|
126
|
+
delete process.env.npm_config_local_prefix;
|
|
127
|
+
} else {
|
|
128
|
+
process.env.npm_config_local_prefix = previousPrefix;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("getConsumerInstallRoot falls back to npm_config_local_prefix and then undefined", () => {
|
|
134
|
+
const previousInitCwd = process.env.INIT_CWD;
|
|
135
|
+
const previousPrefix = process.env.npm_config_local_prefix;
|
|
136
|
+
try {
|
|
137
|
+
delete process.env.INIT_CWD;
|
|
138
|
+
process.env.npm_config_local_prefix = "/tmp/pi-usereq-prefix-root";
|
|
139
|
+
assert.equal(getConsumerInstallRoot(), "/tmp/pi-usereq-prefix-root");
|
|
140
|
+
delete process.env.npm_config_local_prefix;
|
|
141
|
+
assert.equal(getConsumerInstallRoot(), undefined);
|
|
142
|
+
} finally {
|
|
143
|
+
if (previousInitCwd === undefined) {
|
|
144
|
+
delete process.env.INIT_CWD;
|
|
145
|
+
} else {
|
|
146
|
+
process.env.INIT_CWD = previousInitCwd;
|
|
147
|
+
}
|
|
148
|
+
if (previousPrefix === undefined) {
|
|
149
|
+
delete process.env.npm_config_local_prefix;
|
|
150
|
+
} else {
|
|
151
|
+
process.env.npm_config_local_prefix = previousPrefix;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("selectInstallScriptPackageNames returns only packages with lifecycle scripts", () => {
|
|
157
|
+
const packages: NodeModulesPackage[] = [
|
|
158
|
+
{ name: "has-postinstall", scripts: { postinstall: "node install.js" } },
|
|
159
|
+
{ name: "has-install", scripts: { install: "node build.js" } },
|
|
160
|
+
{ name: "no-scripts", scripts: {} },
|
|
161
|
+
{ name: "only-test-script", scripts: { test: "node --test" } },
|
|
162
|
+
{ name: "empty-postinstall", scripts: { postinstall: "" } },
|
|
163
|
+
{ name: "only-prepare-ignored", scripts: { prepare: "node prep.js" } },
|
|
164
|
+
{ name: "@scope/has-preinstall", scripts: { preinstall: "node prep.js" } },
|
|
165
|
+
];
|
|
166
|
+
assert.deepEqual(selectInstallScriptPackageNames(packages), [
|
|
167
|
+
"has-postinstall",
|
|
168
|
+
"has-install",
|
|
169
|
+
"@scope/has-preinstall",
|
|
170
|
+
]);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("mergeAllowScriptsEntries adds name-only approvals and preserves existing denials", () => {
|
|
174
|
+
const existing = { esbuild: true, koffi: false };
|
|
175
|
+
const merged = mergeAllowScriptsEntries(existing, ["esbuild", "pi-usereq", "koffi", "protobufjs"]);
|
|
176
|
+
assert.deepEqual(merged, {
|
|
177
|
+
esbuild: true,
|
|
178
|
+
koffi: false,
|
|
179
|
+
"pi-usereq": true,
|
|
180
|
+
protobufjs: true,
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("mergeAllowScriptsEntries starts from undefined and skips empty names", () => {
|
|
185
|
+
const merged = mergeAllowScriptsEntries(undefined, ["esbuild", "", " "]);
|
|
186
|
+
assert.deepEqual(merged, { esbuild: true });
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test("approvePendingInstallScripts writes name-only allowScripts into the consumer root", () => {
|
|
190
|
+
const consumerRoot = "/tmp/pi-usereq-approval-root";
|
|
191
|
+
const nodeModules = `${consumerRoot}/node_modules`;
|
|
192
|
+
const rootPackageJson = `${consumerRoot}/package.json`;
|
|
193
|
+
const files = new Map<string, string>([
|
|
194
|
+
[`${nodeModules}/esbuild/package.json`, JSON.stringify({ name: "esbuild", scripts: { postinstall: "node install.js" } })],
|
|
195
|
+
[`${nodeModules}/safe-dep/package.json`, JSON.stringify({ name: "safe-dep", scripts: { test: "node --test" } })],
|
|
196
|
+
[`${nodeModules}/@scope/has-install/package.json`, JSON.stringify({ name: "@scope/has-install", scripts: { install: "node build.js" } })],
|
|
197
|
+
[rootPackageJson, JSON.stringify({ name: "pi-extensions", private: true, dependencies: { "pi-usereq": "^0.45.0" } })],
|
|
198
|
+
]);
|
|
199
|
+
const dirs = new Map<string, string[]>([
|
|
200
|
+
[nodeModules, ["esbuild", "safe-dep", "@scope", ".bin"]],
|
|
201
|
+
[`${nodeModules}/@scope`, ["has-install"]],
|
|
202
|
+
]);
|
|
203
|
+
let writtenPath = "";
|
|
204
|
+
let writtenData = "";
|
|
205
|
+
const deps: InstallScriptApprovalDeps = {
|
|
206
|
+
existsSync: (p) => files.has(p) || dirs.has(p),
|
|
207
|
+
readdirSync: (p) => dirs.get(p) ?? [],
|
|
208
|
+
readFileSync: (p) => files.get(p) ?? "",
|
|
209
|
+
writeFileSync: (p, data) => {
|
|
210
|
+
writtenPath = p;
|
|
211
|
+
writtenData = data;
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
const previousInitCwd = process.env.INIT_CWD;
|
|
215
|
+
const previousPrefix = process.env.npm_config_local_prefix;
|
|
216
|
+
try {
|
|
217
|
+
process.env.INIT_CWD = consumerRoot;
|
|
218
|
+
delete process.env.npm_config_local_prefix;
|
|
219
|
+
approvePendingInstallScripts(deps);
|
|
220
|
+
} finally {
|
|
221
|
+
if (previousInitCwd === undefined) {
|
|
222
|
+
delete process.env.INIT_CWD;
|
|
223
|
+
} else {
|
|
224
|
+
process.env.INIT_CWD = previousInitCwd;
|
|
225
|
+
}
|
|
226
|
+
if (previousPrefix === undefined) {
|
|
227
|
+
delete process.env.npm_config_local_prefix;
|
|
228
|
+
} else {
|
|
229
|
+
process.env.npm_config_local_prefix = previousPrefix;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
assert.equal(writtenPath, rootPackageJson);
|
|
233
|
+
const written = JSON.parse(writtenData) as { allowScripts?: Record<string, boolean>; dependencies?: unknown };
|
|
234
|
+
assert.deepEqual(written.allowScripts, { esbuild: true, "@scope/has-install": true });
|
|
235
|
+
assert.ok(written.dependencies, "existing package.json fields MUST be preserved");
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test("approvePendingInstallScripts preserves existing allowScripts and skips when nothing changes", () => {
|
|
239
|
+
const consumerRoot = "/tmp/pi-usereq-noop-root";
|
|
240
|
+
const nodeModules = `${consumerRoot}/node_modules`;
|
|
241
|
+
const rootPackageJson = `${consumerRoot}/package.json`;
|
|
242
|
+
const files = new Map<string, string>([
|
|
243
|
+
[`${nodeModules}/esbuild/package.json`, JSON.stringify({ name: "esbuild", scripts: { postinstall: "node install.js" } })],
|
|
244
|
+
[rootPackageJson, JSON.stringify({ name: "pi-extensions", allowScripts: { esbuild: true, koffi: false } })],
|
|
245
|
+
]);
|
|
246
|
+
const dirs = new Map<string, string[]>([[nodeModules, ["esbuild"]]]);
|
|
247
|
+
let wrote = false;
|
|
248
|
+
const deps: InstallScriptApprovalDeps = {
|
|
249
|
+
existsSync: (p) => files.has(p) || dirs.has(p),
|
|
250
|
+
readdirSync: (p) => dirs.get(p) ?? [],
|
|
251
|
+
readFileSync: (p) => files.get(p) ?? "",
|
|
252
|
+
writeFileSync: () => {
|
|
253
|
+
wrote = true;
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
const previousInitCwd = process.env.INIT_CWD;
|
|
257
|
+
const previousPrefix = process.env.npm_config_local_prefix;
|
|
258
|
+
try {
|
|
259
|
+
process.env.INIT_CWD = consumerRoot;
|
|
260
|
+
delete process.env.npm_config_local_prefix;
|
|
261
|
+
approvePendingInstallScripts(deps);
|
|
262
|
+
} finally {
|
|
263
|
+
if (previousInitCwd === undefined) {
|
|
264
|
+
delete process.env.INIT_CWD;
|
|
265
|
+
} else {
|
|
266
|
+
process.env.INIT_CWD = previousInitCwd;
|
|
267
|
+
}
|
|
268
|
+
if (previousPrefix === undefined) {
|
|
269
|
+
delete process.env.npm_config_local_prefix;
|
|
270
|
+
} else {
|
|
271
|
+
process.env.npm_config_local_prefix = previousPrefix;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
assert.equal(wrote, false);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test("approvePendingInstallScripts skips approval outside an npm install lifecycle", () => {
|
|
278
|
+
let wrote = false;
|
|
279
|
+
const deps: InstallScriptApprovalDeps = {
|
|
280
|
+
existsSync: () => true,
|
|
281
|
+
readdirSync: () => [],
|
|
282
|
+
readFileSync: () => "{}",
|
|
283
|
+
writeFileSync: () => {
|
|
284
|
+
wrote = true;
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
const previousInitCwd = process.env.INIT_CWD;
|
|
288
|
+
const previousPrefix = process.env.npm_config_local_prefix;
|
|
289
|
+
try {
|
|
290
|
+
delete process.env.INIT_CWD;
|
|
291
|
+
delete process.env.npm_config_local_prefix;
|
|
292
|
+
approvePendingInstallScripts(deps);
|
|
293
|
+
} finally {
|
|
294
|
+
if (previousInitCwd === undefined) {
|
|
295
|
+
delete process.env.INIT_CWD;
|
|
296
|
+
} else {
|
|
297
|
+
process.env.INIT_CWD = previousInitCwd;
|
|
298
|
+
}
|
|
299
|
+
if (previousPrefix === undefined) {
|
|
300
|
+
delete process.env.npm_config_local_prefix;
|
|
301
|
+
} else {
|
|
302
|
+
process.env.npm_config_local_prefix = previousPrefix;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
assert.equal(wrote, false);
|
|
306
|
+
});
|