pruneguard 0.1.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/dist/bin.mjs ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import { n as binaryPath, t as PruneguardExecutionError } from "./runtime-BxlGT_W-.mjs";
3
+ import { spawn } from "node:child_process";
4
+ //#region src-js/bin.ts
5
+ try {
6
+ const child = spawn(binaryPath({ allowPathFallback: true }), process.argv.slice(2), { stdio: "inherit" });
7
+ for (const sig of [
8
+ "SIGINT",
9
+ "SIGTERM",
10
+ "SIGHUP"
11
+ ]) process.on(sig, () => child.kill(sig));
12
+ child.on("close", (code, signal) => {
13
+ if (signal) process.kill(process.pid, signal);
14
+ else process.exitCode = code ?? 1;
15
+ });
16
+ } catch (err) {
17
+ console.error(err instanceof PruneguardExecutionError ? err.message : String(err));
18
+ process.exitCode = 2;
19
+ }
20
+ //#endregion
21
+ export {};
@@ -0,0 +1,228 @@
1
+ //#region src-js/runtime.d.ts
2
+ type CommandResult = {
3
+ args: string[];
4
+ cwd?: string;
5
+ exitCode: number;
6
+ stdout: string;
7
+ stderr: string;
8
+ durationMs: number;
9
+ };
10
+ declare class PruneguardExecutionError extends Error {
11
+ code: "PRUNEGUARD_BINARY_NOT_FOUND" | "PRUNEGUARD_EXECUTION_FAILED" | "PRUNEGUARD_JSON_PARSE_FAILED";
12
+ exitCode?: number;
13
+ stdout?: string;
14
+ stderr?: string;
15
+ binaryPath?: string;
16
+ args?: string[];
17
+ constructor(code: PruneguardExecutionError["code"], message: string, details?: {
18
+ exitCode?: number;
19
+ stdout?: string;
20
+ stderr?: string;
21
+ binaryPath?: string;
22
+ args?: string[];
23
+ });
24
+ }
25
+ //#endregion
26
+ //#region src-js/index.d.ts
27
+ type Profile = "production" | "development" | "all";
28
+ type ScanOptions = {
29
+ cwd?: string;
30
+ config?: string;
31
+ paths?: string[];
32
+ profile?: Profile;
33
+ changedSince?: string;
34
+ focus?: string;
35
+ noCache?: boolean;
36
+ noBaseline?: boolean;
37
+ requireFullScope?: boolean;
38
+ };
39
+ type ImpactOptions = {
40
+ cwd?: string;
41
+ config?: string;
42
+ target: string;
43
+ profile?: Profile;
44
+ focus?: string;
45
+ };
46
+ type ExplainOptions = {
47
+ cwd?: string;
48
+ config?: string;
49
+ query: string;
50
+ profile?: Profile;
51
+ focus?: string;
52
+ };
53
+ type DebugResolveOptions = {
54
+ cwd?: string;
55
+ config?: string;
56
+ specifier: string;
57
+ from: string;
58
+ };
59
+ type DebugEntrypointsOptions = {
60
+ cwd?: string;
61
+ config?: string;
62
+ profile?: Profile;
63
+ };
64
+ type AnalysisReport = {
65
+ version: number;
66
+ toolVersion: string;
67
+ cwd: string;
68
+ profile: string;
69
+ summary: {
70
+ totalFiles: number;
71
+ totalPackages: number;
72
+ totalWorkspaces: number;
73
+ totalExports: number;
74
+ totalFindings: number;
75
+ errors: number;
76
+ warnings: number;
77
+ infos: number;
78
+ };
79
+ inventories: {
80
+ files: Array<{
81
+ path: string;
82
+ workspace?: string;
83
+ kind: string;
84
+ role?: "source" | "test" | "story" | "fixture" | "example" | "template" | "benchmark" | "config" | "generated" | "buildOutput";
85
+ }>;
86
+ packages: Array<{
87
+ name: string;
88
+ version?: string;
89
+ workspace: string;
90
+ path: string;
91
+ }>;
92
+ workspaces: Array<{
93
+ name: string;
94
+ path: string;
95
+ packageCount: number;
96
+ }>;
97
+ };
98
+ findings: Array<{
99
+ id: string;
100
+ code: string;
101
+ severity: "error" | "warn" | "info";
102
+ confidence: "high" | "medium" | "low";
103
+ category: string;
104
+ subject: string;
105
+ workspace?: string;
106
+ package?: string;
107
+ message: string;
108
+ evidence: Array<{
109
+ kind: string;
110
+ file?: string;
111
+ line?: number;
112
+ description: string;
113
+ }>;
114
+ suggestion?: string;
115
+ ruleName?: string;
116
+ }>;
117
+ entrypoints: Array<{
118
+ path: string;
119
+ kind: string;
120
+ profile: string;
121
+ workspace?: string;
122
+ source: string;
123
+ }>;
124
+ stats: {
125
+ durationMs: number;
126
+ filesParsed: number;
127
+ filesCached: number;
128
+ filesDiscovered: number;
129
+ filesResolved: number;
130
+ unresolvedSpecifiers: number;
131
+ unresolvedByReason: {
132
+ missingFile: number;
133
+ unsupportedSpecifier: number;
134
+ tsconfigPathMiss: number;
135
+ exportsConditionMiss: number;
136
+ externalized: number;
137
+ };
138
+ resolvedViaExports: number;
139
+ entrypointsDetected: number;
140
+ graphNodes: number;
141
+ graphEdges: number;
142
+ changedFiles: number;
143
+ affectedFiles: number;
144
+ affectedPackages: number;
145
+ affectedEntrypoints: number;
146
+ baselineApplied: boolean;
147
+ baselineProfileMismatch: boolean;
148
+ suppressedFindings: number;
149
+ newFindings: number;
150
+ focusApplied: boolean;
151
+ focusedFiles: number;
152
+ focusedFindings: number;
153
+ fullScopeRequired: boolean;
154
+ partialScope: boolean;
155
+ partialScopeReason?: string;
156
+ confidenceCounts: {
157
+ high: number;
158
+ medium: number;
159
+ low: number;
160
+ };
161
+ parityWarnings: string[];
162
+ cacheHits: number;
163
+ cacheMisses: number;
164
+ cacheEntriesRead: number;
165
+ cacheEntriesWritten: number;
166
+ affectedScopeIncomplete: boolean;
167
+ };
168
+ };
169
+ type MigrationOutput = {
170
+ source: string;
171
+ config: PruneguardConfig;
172
+ warnings: string[];
173
+ };
174
+ type ImpactReport = {
175
+ target: string;
176
+ affectedEntrypoints: string[];
177
+ affectedPackages: string[];
178
+ affectedFiles: string[];
179
+ evidence: Array<{
180
+ kind: string;
181
+ file?: string;
182
+ line?: number;
183
+ description: string;
184
+ }>;
185
+ focusFiltered: boolean;
186
+ };
187
+ type ExplainReport = {
188
+ query: string;
189
+ matchedNode?: string;
190
+ queryKind: "finding" | "file" | "export";
191
+ proofs: Array<{
192
+ node: string;
193
+ relationship: string;
194
+ children: ExplainReport["proofs"];
195
+ }>;
196
+ relatedFindings: AnalysisReport["findings"];
197
+ focusFiltered: boolean;
198
+ };
199
+ type PruneguardConfig = Record<string, unknown>;
200
+ declare function scan(options?: ScanOptions): Promise<AnalysisReport>;
201
+ /** @experimental */
202
+ declare function scanDot(options?: ScanOptions): Promise<string>;
203
+ declare function impact(options: ImpactOptions): Promise<ImpactReport>;
204
+ declare function explain(options: ExplainOptions): Promise<ExplainReport>;
205
+ declare function loadConfig(options?: {
206
+ cwd?: string;
207
+ config?: string;
208
+ }): Promise<PruneguardConfig>;
209
+ declare function schemaPath(): string;
210
+ declare function binaryPath(): string;
211
+ declare function run(args: string[], options?: {
212
+ cwd?: string;
213
+ }): Promise<CommandResult>;
214
+ declare function debugResolve(options: DebugResolveOptions): Promise<string>;
215
+ declare function debugEntrypoints(options?: DebugEntrypointsOptions): Promise<string[]>;
216
+ /** @experimental */
217
+ declare function migrateKnip(options?: {
218
+ cwd?: string;
219
+ file?: string;
220
+ }): Promise<MigrationOutput>;
221
+ /** @experimental */
222
+ declare function migrateDepcruise(options?: {
223
+ cwd?: string;
224
+ file?: string;
225
+ node?: boolean;
226
+ }): Promise<MigrationOutput>;
227
+ //#endregion
228
+ export { AnalysisReport, type CommandResult, DebugEntrypointsOptions, DebugResolveOptions, ExplainOptions, ExplainReport, ImpactOptions, ImpactReport, MigrationOutput, Profile, PruneguardConfig, PruneguardExecutionError, ScanOptions, binaryPath, debugEntrypoints, debugResolve, explain, impact, loadConfig, migrateDepcruise, migrateKnip, run, scan, scanDot, schemaPath };
package/dist/index.mjs ADDED
@@ -0,0 +1,144 @@
1
+ import { n as binaryPath$1, r as run$1, t as PruneguardExecutionError } from "./runtime-BxlGT_W-.mjs";
2
+ import { fileURLToPath } from "node:url";
3
+ //#region src-js/index.ts
4
+ function parseJson(result) {
5
+ try {
6
+ return JSON.parse(result.stdout);
7
+ } catch {
8
+ throw new PruneguardExecutionError("PRUNEGUARD_JSON_PARSE_FAILED", `Failed to parse pruneguard JSON output: ${result.stderr || result.stdout.slice(0, 200)}`, {
9
+ exitCode: result.exitCode,
10
+ stdout: result.stdout,
11
+ stderr: result.stderr,
12
+ args: result.args
13
+ });
14
+ }
15
+ }
16
+ function requireSuccess(result) {
17
+ if (result.exitCode !== 0) throw new PruneguardExecutionError("PRUNEGUARD_EXECUTION_FAILED", `pruneguard exited with code ${result.exitCode}: ${result.stderr}`, {
18
+ exitCode: result.exitCode,
19
+ stdout: result.stdout,
20
+ stderr: result.stderr,
21
+ args: result.args
22
+ });
23
+ }
24
+ function pushGlobalFlags(args, options) {
25
+ if (options.config) args.push("--config", options.config);
26
+ if (options.profile) args.push("--profile", options.profile);
27
+ if (options.focus) args.push("--focus", options.focus);
28
+ }
29
+ async function scan(options = {}) {
30
+ const args = [
31
+ "--format",
32
+ "json",
33
+ "--severity",
34
+ "info"
35
+ ];
36
+ pushGlobalFlags(args, options);
37
+ if (options.changedSince) args.push("--changed-since", options.changedSince);
38
+ if (options.noCache) args.push("--no-cache");
39
+ if (options.noBaseline) args.push("--no-baseline");
40
+ if (options.requireFullScope) args.push("--require-full-scope");
41
+ args.push("scan");
42
+ if (options.paths?.length) args.push(...options.paths);
43
+ const result = await run$1(args, { cwd: options.cwd });
44
+ if (result.exitCode !== 0 && result.exitCode !== 1) requireSuccess(result);
45
+ return parseJson(result);
46
+ }
47
+ /** @experimental */
48
+ async function scanDot(options = {}) {
49
+ const args = [
50
+ "--format",
51
+ "dot",
52
+ "--severity",
53
+ "info"
54
+ ];
55
+ pushGlobalFlags(args, options);
56
+ if (options.changedSince) args.push("--changed-since", options.changedSince);
57
+ if (options.noCache) args.push("--no-cache");
58
+ if (options.noBaseline) args.push("--no-baseline");
59
+ if (options.requireFullScope) args.push("--require-full-scope");
60
+ args.push("scan");
61
+ if (options.paths?.length) args.push(...options.paths);
62
+ const result = await run$1(args, { cwd: options.cwd });
63
+ if (result.exitCode !== 0 && result.exitCode !== 1) requireSuccess(result);
64
+ return result.stdout;
65
+ }
66
+ async function impact(options) {
67
+ const args = ["--format", "json"];
68
+ pushGlobalFlags(args, options);
69
+ args.push("impact", options.target);
70
+ const result = await run$1(args, { cwd: options.cwd });
71
+ requireSuccess(result);
72
+ return parseJson(result);
73
+ }
74
+ async function explain(options) {
75
+ const args = ["--format", "json"];
76
+ pushGlobalFlags(args, options);
77
+ args.push("explain", options.query);
78
+ const result = await run$1(args, { cwd: options.cwd });
79
+ requireSuccess(result);
80
+ return parseJson(result);
81
+ }
82
+ async function loadConfig(options) {
83
+ const args = [];
84
+ if (options?.config) args.push("--config", options.config);
85
+ args.push("print-config");
86
+ const result = await run$1(args, { cwd: options?.cwd });
87
+ requireSuccess(result);
88
+ return parseJson(result);
89
+ }
90
+ function schemaPath() {
91
+ return fileURLToPath(new URL("../configuration_schema.json", import.meta.url));
92
+ }
93
+ function binaryPath() {
94
+ return binaryPath$1();
95
+ }
96
+ function run(args, options) {
97
+ return run$1(args, options);
98
+ }
99
+ async function debugResolve(options) {
100
+ const args = [];
101
+ if (options.config) args.push("--config", options.config);
102
+ args.push("debug", "resolve", "--from", options.from, options.specifier);
103
+ const result = await run$1(args, { cwd: options.cwd });
104
+ requireSuccess(result);
105
+ return result.stdout.trimEnd();
106
+ }
107
+ async function debugEntrypoints(options = {}) {
108
+ const args = [];
109
+ if (options.config) args.push("--config", options.config);
110
+ if (options.profile) args.push("--profile", options.profile);
111
+ args.push("debug", "entrypoints");
112
+ const result = await run$1(args, { cwd: options.cwd });
113
+ requireSuccess(result);
114
+ return result.stdout.trimEnd().split("\n").filter(Boolean);
115
+ }
116
+ /** @experimental */
117
+ async function migrateKnip(options = {}) {
118
+ const args = [
119
+ "--format",
120
+ "json",
121
+ "migrate",
122
+ "knip"
123
+ ];
124
+ if (options.file) args.push(options.file);
125
+ const result = await run$1(args, { cwd: options.cwd });
126
+ requireSuccess(result);
127
+ return parseJson(result);
128
+ }
129
+ /** @experimental */
130
+ async function migrateDepcruise(options = {}) {
131
+ const args = [
132
+ "--format",
133
+ "json",
134
+ "migrate",
135
+ "depcruise"
136
+ ];
137
+ if (options.node) args.push("--node");
138
+ if (options.file) args.push(options.file);
139
+ const result = await run$1(args, { cwd: options.cwd });
140
+ requireSuccess(result);
141
+ return parseJson(result);
142
+ }
143
+ //#endregion
144
+ export { PruneguardExecutionError, binaryPath, debugEntrypoints, debugResolve, explain, impact, loadConfig, migrateDepcruise, migrateKnip, run, scan, scanDot, schemaPath };
@@ -0,0 +1,132 @@
1
+ import { createRequire } from "node:module";
2
+ import { fileURLToPath } from "node:url";
3
+ import { execFileSync, spawn } from "node:child_process";
4
+ import { existsSync } from "node:fs";
5
+ import { dirname, join } from "node:path";
6
+ //#region src-js/runtime.ts
7
+ const require = createRequire(import.meta.url);
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ var PruneguardExecutionError = class extends Error {
10
+ code;
11
+ exitCode;
12
+ stdout;
13
+ stderr;
14
+ binaryPath;
15
+ args;
16
+ constructor(code, message, details) {
17
+ super(message);
18
+ this.name = "PruneguardExecutionError";
19
+ this.code = code;
20
+ this.exitCode = details?.exitCode;
21
+ this.stdout = details?.stdout;
22
+ this.stderr = details?.stderr;
23
+ this.binaryPath = details?.binaryPath;
24
+ this.args = details?.args;
25
+ }
26
+ };
27
+ const PLATFORM_PACKAGES = {
28
+ "darwin-arm64": ["@pruneguard/cli-darwin-arm64"],
29
+ "darwin-x64": ["@pruneguard/cli-darwin-x64"],
30
+ "linux-arm64": ["@pruneguard/cli-linux-arm64-gnu", "@pruneguard/cli-linux-arm64-musl"],
31
+ "linux-x64": ["@pruneguard/cli-linux-x64-gnu", "@pruneguard/cli-linux-x64-musl"],
32
+ "win32-arm64": ["@pruneguard/cli-win32-arm64-msvc"],
33
+ "win32-x64": ["@pruneguard/cli-win32-x64-msvc"]
34
+ };
35
+ function exeName() {
36
+ return process.platform === "win32" ? "pruneguard.exe" : "pruneguard";
37
+ }
38
+ function findPlatformBinary() {
39
+ const candidates = PLATFORM_PACKAGES[`${process.platform}-${process.arch === "arm64" ? "arm64" : "x64"}`];
40
+ if (!candidates) return void 0;
41
+ for (const pkg of candidates) try {
42
+ const binPath = join(dirname(require.resolve(`${pkg}/package.json`)), "bin", exeName());
43
+ if (existsSync(binPath)) return binPath;
44
+ } catch {
45
+ continue;
46
+ }
47
+ }
48
+ function findDevBinary() {
49
+ const candidates = [join(__dirname, "..", "..", "..", "target", "release", exeName()), join(__dirname, "..", "..", "..", "target", "debug", exeName())];
50
+ for (const candidate of candidates) if (existsSync(candidate)) return candidate;
51
+ }
52
+ function findPathBinary() {
53
+ try {
54
+ const binPath = execFileSync(process.platform === "win32" ? "where" : "which", [exeName()], {
55
+ encoding: "utf8",
56
+ stdio: [
57
+ "pipe",
58
+ "pipe",
59
+ "pipe"
60
+ ]
61
+ }).trim().split("\n")[0];
62
+ if (binPath) return binPath;
63
+ } catch {}
64
+ }
65
+ let cachedBinaryPath;
66
+ function binaryPath(options) {
67
+ if (cachedBinaryPath) return cachedBinaryPath;
68
+ const envPath = process.env.PRUNEGUARD_BINARY;
69
+ if (envPath) {
70
+ if (!existsSync(envPath)) throw new PruneguardExecutionError("PRUNEGUARD_BINARY_NOT_FOUND", `PRUNEGUARD_BINARY points to ${envPath} but the file does not exist`, { binaryPath: envPath });
71
+ cachedBinaryPath = envPath;
72
+ return envPath;
73
+ }
74
+ const platformBin = findPlatformBinary();
75
+ if (platformBin) {
76
+ cachedBinaryPath = platformBin;
77
+ return platformBin;
78
+ }
79
+ const devBin = findDevBinary();
80
+ if (devBin) {
81
+ cachedBinaryPath = devBin;
82
+ return devBin;
83
+ }
84
+ if (options?.allowPathFallback) {
85
+ const pathBin = findPathBinary();
86
+ if (pathBin) {
87
+ cachedBinaryPath = pathBin;
88
+ return pathBin;
89
+ }
90
+ }
91
+ throw new PruneguardExecutionError("PRUNEGUARD_BINARY_NOT_FOUND", "Could not find the pruneguard binary. Install a platform-specific package or set PRUNEGUARD_BINARY.");
92
+ }
93
+ function run(args, options) {
94
+ const binary = binaryPath();
95
+ const start = performance.now();
96
+ return new Promise((resolve, reject) => {
97
+ const child = spawn(binary, args, {
98
+ cwd: options?.cwd,
99
+ stdio: [
100
+ "ignore",
101
+ "pipe",
102
+ "pipe"
103
+ ]
104
+ });
105
+ let stdout = "";
106
+ let stderr = "";
107
+ child.stdout.on("data", (chunk) => {
108
+ stdout += chunk.toString();
109
+ });
110
+ child.stderr.on("data", (chunk) => {
111
+ stderr += chunk.toString();
112
+ });
113
+ child.on("error", (err) => {
114
+ reject(new PruneguardExecutionError("PRUNEGUARD_EXECUTION_FAILED", `Failed to spawn pruneguard: ${err.message}`, {
115
+ binaryPath: binary,
116
+ args
117
+ }));
118
+ });
119
+ child.on("close", (exitCode) => {
120
+ resolve({
121
+ args,
122
+ cwd: options?.cwd,
123
+ exitCode: exitCode ?? 1,
124
+ stdout,
125
+ stderr,
126
+ durationMs: Math.round(performance.now() - start)
127
+ });
128
+ });
129
+ });
130
+ }
131
+ //#endregion
132
+ export { binaryPath as n, run as r, PruneguardExecutionError as t };
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "pruneguard",
3
+ "version": "0.1.0",
4
+ "description": "Repo truth engine for JS/TS monorepos",
5
+ "keywords": [
6
+ "javascript",
7
+ "typescript",
8
+ "monorepo",
9
+ "graph",
10
+ "unused-code",
11
+ "dead-code",
12
+ "dependency-graph",
13
+ "architecture"
14
+ ],
15
+ "homepage": "https://github.com/user/pruneguard",
16
+ "bugs": "https://github.com/user/pruneguard/issues",
17
+ "license": "MIT",
18
+ "author": "pruneguard contributors",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/user/pruneguard",
22
+ "directory": "npm/pruneguard"
23
+ },
24
+ "bin": {
25
+ "pruneguard": "bin/pruneguard"
26
+ },
27
+ "files": [
28
+ "configuration_schema.json",
29
+ "report_schema.json",
30
+ "dist",
31
+ "README.md",
32
+ "bin/pruneguard"
33
+ ],
34
+ "type": "module",
35
+ "main": "dist/index.mjs",
36
+ "types": "dist/index.d.mts",
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/index.d.mts",
40
+ "default": "./dist/index.mjs"
41
+ }
42
+ },
43
+ "optionalDependencies": {
44
+ "@pruneguard/cli-darwin-arm64": "0.1.0",
45
+ "@pruneguard/cli-darwin-x64": "0.1.0",
46
+ "@pruneguard/cli-linux-arm64-gnu": "0.1.0",
47
+ "@pruneguard/cli-linux-arm64-musl": "0.1.0",
48
+ "@pruneguard/cli-linux-x64-gnu": "0.1.0",
49
+ "@pruneguard/cli-linux-x64-musl": "0.1.0",
50
+ "@pruneguard/cli-win32-arm64-msvc": "0.1.0",
51
+ "@pruneguard/cli-win32-x64-msvc": "0.1.0"
52
+ },
53
+ "engines": {
54
+ "node": ">=18.0.0"
55
+ },
56
+ "preferUnplugged": true
57
+ }