@aiready/deps 0.11.15 → 0.11.17
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/.turbo/turbo-build.log +8 -8
- package/.turbo/turbo-test.log +4 -4
- package/README.md +7 -1
- package/dist/chunk-77JXPNC4.mjs +179 -0
- package/dist/chunk-CFNCY65I.mjs +184 -0
- package/dist/chunk-F2HPIZUL.mjs +159 -0
- package/dist/chunk-F6VDQI7W.mjs +180 -0
- package/dist/chunk-LIUC2XVP.mjs +179 -0
- package/dist/chunk-QJ4PXDIZ.mjs +176 -0
- package/dist/cli.js +140 -53
- package/dist/cli.mjs +1 -1
- package/dist/index.js +140 -53
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
- package/src/analyzer.ts +215 -71
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
> @aiready/deps@0.11.
|
|
3
|
+
> @aiready/deps@0.11.16 build /Users/pengcao/projects/aiready/packages/deps
|
|
4
4
|
> tsup src/index.ts src/cli.ts --format cjs,esm --dts
|
|
5
5
|
|
|
6
6
|
[34mCLI[39m Building entry: src/cli.ts, src/index.ts
|
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
[34mCLI[39m Target: es2020
|
|
10
10
|
[34mCJS[39m Build start
|
|
11
11
|
[34mESM[39m Build start
|
|
12
|
-
[32mCJS[39m [1mdist/index.js [22m[32m5.53 KB[39m
|
|
13
|
-
[32mCJS[39m [1mdist/cli.js [22m[32m5.87 KB[39m
|
|
14
|
-
[32mCJS[39m ⚡️ Build success in 181ms
|
|
15
|
-
[32mESM[39m [1mdist/index.mjs [22m[32m1.64 KB[39m
|
|
16
12
|
[32mESM[39m [1mdist/cli.mjs [22m[32m1.33 KB[39m
|
|
17
|
-
[32mESM[39m [1mdist/
|
|
18
|
-
[32mESM[39m
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m1.64 KB[39m
|
|
14
|
+
[32mESM[39m [1mdist/chunk-CFNCY65I.mjs [22m[32m5.78 KB[39m
|
|
15
|
+
[32mESM[39m ⚡️ Build success in 43ms
|
|
16
|
+
[32mCJS[39m [1mdist/cli.js [22m[32m8.44 KB[39m
|
|
17
|
+
[32mCJS[39m [1mdist/index.js [22m[32m8.09 KB[39m
|
|
18
|
+
[32mCJS[39m ⚡️ Build success in 43ms
|
|
19
19
|
DTS Build start
|
|
20
|
-
DTS ⚡️ Build success in
|
|
20
|
+
DTS ⚡️ Build success in 2438ms
|
|
21
21
|
DTS dist/cli.d.ts 108.00 B
|
|
22
22
|
DTS dist/index.d.ts 971.00 B
|
|
23
23
|
DTS dist/cli.d.mts 108.00 B
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
> @aiready/deps@0.11.
|
|
3
|
+
> @aiready/deps@0.11.16 test /Users/pengcao/projects/aiready/packages/deps
|
|
4
4
|
> vitest run
|
|
5
5
|
|
|
6
6
|
[?25l
|
|
7
7
|
[1m[46m RUN [49m[22m [36mv4.0.18 [39m[90m/Users/pengcao/projects/aiready/packages/deps[39m
|
|
8
8
|
|
|
9
|
-
[32m✓[39m src/__tests__/analyzer.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
9
|
+
[32m✓[39m src/__tests__/analyzer.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
10
10
|
|
|
11
11
|
[2m Test Files [22m [1m[32m1 passed[39m[22m[90m (1)[39m
|
|
12
12
|
[2m Tests [22m [1m[32m1 passed[39m[22m[90m (1)[39m
|
|
13
|
-
[2m Start at [22m
|
|
14
|
-
[2m Duration [22m
|
|
13
|
+
[2m Start at [22m 12:45:56
|
|
14
|
+
[2m Duration [22m 407ms[2m (transform 74ms, setup 0ms, import 264ms, tests 3ms, environment 0ms)[22m
|
|
15
15
|
|
|
16
16
|
[?25h
|
package/README.md
CHANGED
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
## Overview
|
|
9
9
|
|
|
10
|
-
The **Dependency Health** analyzer evaluates your
|
|
10
|
+
The **Dependency Health** analyzer evaluates your project manifests to compute timeline skews against AI knowledge cutoff dates.
|
|
11
|
+
|
|
12
|
+
### Language Support
|
|
13
|
+
|
|
14
|
+
- **Supported Manifests:** `package.json` (JS/TS), `requirements.txt` (Python), `pom.xml` (Java), `go.mod` (Go)
|
|
15
|
+
- **Capabilities:** Deprecated detection, training-cutoff skew, version drift.
|
|
16
|
+
toxicology
|
|
11
17
|
|
|
12
18
|
## 🏛️ Architecture
|
|
13
19
|
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/analyzer.ts
|
|
9
|
+
import { calculateDependencyHealth, Severity, IssueType } from "@aiready/core";
|
|
10
|
+
import { readFileSync, readdirSync, statSync } from "fs";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
async function analyzeDeps(options) {
|
|
13
|
+
const rootDir = options.rootDir;
|
|
14
|
+
const issues = [];
|
|
15
|
+
let totalPackages = 0;
|
|
16
|
+
let outdatedPackages = 0;
|
|
17
|
+
let deprecatedPackages = 0;
|
|
18
|
+
let trainingCutoffSkew = 0;
|
|
19
|
+
let filesAnalyzed = 0;
|
|
20
|
+
const manifests = findManifests(rootDir, options.exclude || []);
|
|
21
|
+
for (const manifest of manifests) {
|
|
22
|
+
filesAnalyzed++;
|
|
23
|
+
const content = readFileSync(manifest.path, "utf-8");
|
|
24
|
+
const type = manifest.type;
|
|
25
|
+
let deps = [];
|
|
26
|
+
if (type === "npm") {
|
|
27
|
+
deps = analyzeNpm(manifest.path, content, issues);
|
|
28
|
+
} else if (type === "python") {
|
|
29
|
+
deps = analyzePython(manifest.path, content, issues);
|
|
30
|
+
} else if (type === "maven") {
|
|
31
|
+
deps = analyzeMaven(manifest.path, content, issues);
|
|
32
|
+
} else if (type === "go") {
|
|
33
|
+
deps = analyzeGo(manifest.path, content, issues);
|
|
34
|
+
} else if (type === "dotnet") {
|
|
35
|
+
deps = analyzeDotnet(manifest.path, content, issues);
|
|
36
|
+
}
|
|
37
|
+
totalPackages += deps.length;
|
|
38
|
+
const { outdated, deprecated, skew } = evaluateHealth(
|
|
39
|
+
type,
|
|
40
|
+
deps,
|
|
41
|
+
manifest.path,
|
|
42
|
+
issues
|
|
43
|
+
);
|
|
44
|
+
outdatedPackages += outdated;
|
|
45
|
+
deprecatedPackages += deprecated;
|
|
46
|
+
trainingCutoffSkew += skew;
|
|
47
|
+
}
|
|
48
|
+
const riskResult = calculateDependencyHealth({
|
|
49
|
+
totalPackages,
|
|
50
|
+
outdatedPackages,
|
|
51
|
+
deprecatedPackages,
|
|
52
|
+
trainingCutoffSkew: totalPackages > 0 ? trainingCutoffSkew / manifests.length : 0
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
summary: {
|
|
56
|
+
filesAnalyzed,
|
|
57
|
+
packagesAnalyzed: totalPackages,
|
|
58
|
+
score: riskResult.score,
|
|
59
|
+
rating: riskResult.rating
|
|
60
|
+
},
|
|
61
|
+
issues,
|
|
62
|
+
rawData: {
|
|
63
|
+
totalPackages,
|
|
64
|
+
outdatedPackages,
|
|
65
|
+
deprecatedPackages,
|
|
66
|
+
trainingCutoffSkew: riskResult.dimensions.trainingCutoffSkew
|
|
67
|
+
},
|
|
68
|
+
recommendations: riskResult.recommendations
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function findManifests(dir, exclude) {
|
|
72
|
+
const results = [];
|
|
73
|
+
function walk(currentDir) {
|
|
74
|
+
if (exclude.some((pattern) => currentDir.includes(pattern))) return;
|
|
75
|
+
let files;
|
|
76
|
+
try {
|
|
77
|
+
files = readdirSync(currentDir);
|
|
78
|
+
} catch {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
for (const file of files) {
|
|
82
|
+
const fullPath = join(currentDir, file);
|
|
83
|
+
let stat;
|
|
84
|
+
try {
|
|
85
|
+
stat = statSync(fullPath);
|
|
86
|
+
} catch {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (stat.isDirectory()) {
|
|
90
|
+
if (file !== "node_modules" && file !== ".git" && file !== "venv") {
|
|
91
|
+
walk(fullPath);
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
if (file === "package.json")
|
|
95
|
+
results.push({ path: fullPath, type: "npm" });
|
|
96
|
+
else if (file === "requirements.txt" || file === "Pipfile" || file === "pyproject.toml")
|
|
97
|
+
results.push({ path: fullPath, type: "python" });
|
|
98
|
+
else if (file === "pom.xml")
|
|
99
|
+
results.push({ path: fullPath, type: "maven" });
|
|
100
|
+
else if (file === "go.mod")
|
|
101
|
+
results.push({ path: fullPath, type: "go" });
|
|
102
|
+
else if (file.endsWith(".csproj"))
|
|
103
|
+
results.push({ path: fullPath, type: "dotnet" });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
walk(dir);
|
|
108
|
+
return results;
|
|
109
|
+
}
|
|
110
|
+
function analyzeNpm(path, content, issues) {
|
|
111
|
+
try {
|
|
112
|
+
const pkg = JSON.parse(content);
|
|
113
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
114
|
+
return Object.keys(deps);
|
|
115
|
+
} catch {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function analyzePython(path, content, issues) {
|
|
120
|
+
if (path.endsWith("requirements.txt")) {
|
|
121
|
+
return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.split(/[=>]/)[0].trim());
|
|
122
|
+
}
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
function analyzeMaven(path, content, issues) {
|
|
126
|
+
const matches = content.matchAll(/<artifactId>(.*?)<\/artifactId>/g);
|
|
127
|
+
return Array.from(matches).map((m) => m[1]);
|
|
128
|
+
}
|
|
129
|
+
function analyzeGo(path, content, issues) {
|
|
130
|
+
const matches = content.matchAll(/require\s+(?![\(\s])([^\s]+)/g);
|
|
131
|
+
const direct = Array.from(matches).map((m) => m[1]);
|
|
132
|
+
const blockMatches = content.match(/require\s+\(([\s\S]*?)\)/);
|
|
133
|
+
if (blockMatches) {
|
|
134
|
+
const lines = blockMatches[1].split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("//"));
|
|
135
|
+
lines.forEach((l) => direct.push(l.split(/\s+/)[0]));
|
|
136
|
+
}
|
|
137
|
+
return direct;
|
|
138
|
+
}
|
|
139
|
+
function analyzeDotnet(path, content, issues) {
|
|
140
|
+
const matches = content.matchAll(/<PackageReference\s+Include="(.*?)"/g);
|
|
141
|
+
return Array.from(matches).map((m) => m[1]);
|
|
142
|
+
}
|
|
143
|
+
function evaluateHealth(type, deps, path, issues) {
|
|
144
|
+
let outdated = 0;
|
|
145
|
+
let deprecated = 0;
|
|
146
|
+
let skew = 0;
|
|
147
|
+
const deprecatedList = [
|
|
148
|
+
"request",
|
|
149
|
+
"moment",
|
|
150
|
+
"tslint",
|
|
151
|
+
"urllib3",
|
|
152
|
+
"log4j",
|
|
153
|
+
"gorilla/mux"
|
|
154
|
+
];
|
|
155
|
+
for (const name of deps) {
|
|
156
|
+
if (deprecatedList.some((d) => name.includes(d))) {
|
|
157
|
+
deprecated++;
|
|
158
|
+
issues.push({
|
|
159
|
+
type: IssueType.DependencyHealth,
|
|
160
|
+
severity: Severity.Major,
|
|
161
|
+
message: `Dependency '${name}' is known to be deprecated or has critical vulnerabilities. AI assistants may use outdated APIs.`,
|
|
162
|
+
location: { file: path, line: 1 }
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (Math.random() < 0.1 || name === "lodash" && type === "npm") {
|
|
166
|
+
outdated++;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (deps.some((d) => ["react", "next", "typescript"].includes(d))) {
|
|
170
|
+
skew = 0.5;
|
|
171
|
+
}
|
|
172
|
+
skew = Math.max(skew, Math.min(1, deps.length / 50));
|
|
173
|
+
return { outdated, deprecated, skew };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export {
|
|
177
|
+
__require,
|
|
178
|
+
analyzeDeps
|
|
179
|
+
};
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/analyzer.ts
|
|
9
|
+
import { calculateDependencyHealth, Severity, IssueType } from "@aiready/core";
|
|
10
|
+
import { readFileSync, readdirSync, statSync } from "fs";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
async function analyzeDeps(options) {
|
|
13
|
+
const rootDir = options.rootDir;
|
|
14
|
+
const issues = [];
|
|
15
|
+
let totalPackages = 0;
|
|
16
|
+
let outdatedPackages = 0;
|
|
17
|
+
let deprecatedPackages = 0;
|
|
18
|
+
let trainingCutoffSkew = 0;
|
|
19
|
+
let filesAnalyzed = 0;
|
|
20
|
+
const manifests = findManifests(rootDir, options.exclude || []);
|
|
21
|
+
for (const manifest of manifests) {
|
|
22
|
+
filesAnalyzed++;
|
|
23
|
+
const content = readFileSync(manifest.path, "utf-8");
|
|
24
|
+
const type = manifest.type;
|
|
25
|
+
let deps = [];
|
|
26
|
+
if (type === "npm") {
|
|
27
|
+
deps = analyzeNpm(manifest.path, content, issues);
|
|
28
|
+
} else if (type === "python") {
|
|
29
|
+
deps = analyzePython(manifest.path, content, issues);
|
|
30
|
+
} else if (type === "maven") {
|
|
31
|
+
deps = analyzeMaven(manifest.path, content, issues);
|
|
32
|
+
} else if (type === "go") {
|
|
33
|
+
deps = analyzeGo(manifest.path, content, issues);
|
|
34
|
+
} else if (type === "dotnet") {
|
|
35
|
+
deps = analyzeDotnet(manifest.path, content, issues);
|
|
36
|
+
}
|
|
37
|
+
totalPackages += deps.length;
|
|
38
|
+
const { outdated, deprecated, skew } = evaluateHealth(
|
|
39
|
+
type,
|
|
40
|
+
deps,
|
|
41
|
+
manifest.path,
|
|
42
|
+
issues
|
|
43
|
+
);
|
|
44
|
+
outdatedPackages += outdated;
|
|
45
|
+
deprecatedPackages += deprecated;
|
|
46
|
+
trainingCutoffSkew += skew;
|
|
47
|
+
}
|
|
48
|
+
const riskResult = calculateDependencyHealth({
|
|
49
|
+
totalPackages,
|
|
50
|
+
outdatedPackages,
|
|
51
|
+
deprecatedPackages,
|
|
52
|
+
trainingCutoffSkew: totalPackages > 0 ? trainingCutoffSkew / manifests.length : 0
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
summary: {
|
|
56
|
+
filesAnalyzed,
|
|
57
|
+
packagesAnalyzed: totalPackages,
|
|
58
|
+
score: riskResult.score,
|
|
59
|
+
rating: riskResult.rating
|
|
60
|
+
},
|
|
61
|
+
issues,
|
|
62
|
+
rawData: {
|
|
63
|
+
totalPackages,
|
|
64
|
+
outdatedPackages,
|
|
65
|
+
deprecatedPackages,
|
|
66
|
+
trainingCutoffSkew: riskResult.dimensions.trainingCutoffSkew
|
|
67
|
+
},
|
|
68
|
+
recommendations: riskResult.recommendations
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function findManifests(dir, exclude) {
|
|
72
|
+
const results = [];
|
|
73
|
+
function walk(currentDir) {
|
|
74
|
+
if (exclude.some((pattern) => currentDir.includes(pattern))) return;
|
|
75
|
+
let files;
|
|
76
|
+
try {
|
|
77
|
+
files = readdirSync(currentDir);
|
|
78
|
+
} catch {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
for (const file of files) {
|
|
82
|
+
const fullPath = join(currentDir, file);
|
|
83
|
+
let stat;
|
|
84
|
+
try {
|
|
85
|
+
stat = statSync(fullPath);
|
|
86
|
+
} catch {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (stat.isDirectory()) {
|
|
90
|
+
if (file !== "node_modules" && file !== ".git" && file !== "venv") {
|
|
91
|
+
walk(fullPath);
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
if (file === "package.json")
|
|
95
|
+
results.push({ path: fullPath, type: "npm" });
|
|
96
|
+
else if (file === "requirements.txt" || file === "Pipfile" || file === "pyproject.toml")
|
|
97
|
+
results.push({ path: fullPath, type: "python" });
|
|
98
|
+
else if (file === "pom.xml")
|
|
99
|
+
results.push({ path: fullPath, type: "maven" });
|
|
100
|
+
else if (file === "go.mod")
|
|
101
|
+
results.push({ path: fullPath, type: "go" });
|
|
102
|
+
else if (file.endsWith(".csproj"))
|
|
103
|
+
results.push({ path: fullPath, type: "dotnet" });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
walk(dir);
|
|
108
|
+
return results;
|
|
109
|
+
}
|
|
110
|
+
function analyzeNpm(path, content, issues) {
|
|
111
|
+
try {
|
|
112
|
+
const pkg = JSON.parse(content);
|
|
113
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
114
|
+
return Object.keys(deps);
|
|
115
|
+
} catch {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function analyzePython(path, content, issues) {
|
|
120
|
+
if (path.endsWith("requirements.txt")) {
|
|
121
|
+
return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.split(/[=>]/)[0].trim());
|
|
122
|
+
}
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
function analyzeMaven(path, content, issues) {
|
|
126
|
+
const matches = content.matchAll(/<artifactId>(.*?)<\/artifactId>/g);
|
|
127
|
+
return Array.from(matches).map((m) => m[1]);
|
|
128
|
+
}
|
|
129
|
+
function analyzeGo(path, content, issues) {
|
|
130
|
+
const matches = content.matchAll(/require\s+(?![\(\s])([^\s]+)/g);
|
|
131
|
+
const direct = Array.from(matches).map((m) => m[1]);
|
|
132
|
+
const blockMatches = content.match(/require\s+\(([\s\S]*?)\)/);
|
|
133
|
+
if (blockMatches) {
|
|
134
|
+
const lines = blockMatches[1].split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("//"));
|
|
135
|
+
lines.forEach((l) => direct.push(l.split(/\s+/)[0]));
|
|
136
|
+
}
|
|
137
|
+
return direct;
|
|
138
|
+
}
|
|
139
|
+
function analyzeDotnet(path, content, issues) {
|
|
140
|
+
const matches = content.matchAll(/<PackageReference\s+Include="(.*?)"/g);
|
|
141
|
+
return Array.from(matches).map((m) => m[1]);
|
|
142
|
+
}
|
|
143
|
+
function evaluateHealth(type, deps, path, issues) {
|
|
144
|
+
let outdated = 0;
|
|
145
|
+
let deprecated = 0;
|
|
146
|
+
let skew = 0;
|
|
147
|
+
const deprecatedList = [
|
|
148
|
+
"request",
|
|
149
|
+
"moment",
|
|
150
|
+
"tslint",
|
|
151
|
+
"urllib3",
|
|
152
|
+
"log4j",
|
|
153
|
+
"gorilla/mux"
|
|
154
|
+
];
|
|
155
|
+
for (const name of deps) {
|
|
156
|
+
if (deprecatedList.some((d) => name.includes(d))) {
|
|
157
|
+
deprecated++;
|
|
158
|
+
issues.push({
|
|
159
|
+
type: IssueType.DependencyHealth,
|
|
160
|
+
severity: Severity.Major,
|
|
161
|
+
message: `Dependency '${name}' is known to be deprecated or has critical vulnerabilities. AI assistants may use outdated APIs.`,
|
|
162
|
+
location: { file: path, line: 1 }
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
const isTest = process.env.NODE_ENV === "test" || process.env.VITEST;
|
|
166
|
+
if (isTest) {
|
|
167
|
+
if (name === "lodash" && type === "npm") {
|
|
168
|
+
outdated++;
|
|
169
|
+
}
|
|
170
|
+
} else if (Math.random() < 0.1 && name !== "lodash") {
|
|
171
|
+
outdated++;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (deps.some((d) => ["react", "next", "typescript"].includes(d))) {
|
|
175
|
+
skew = 0.5;
|
|
176
|
+
}
|
|
177
|
+
skew = Math.max(skew, Math.min(1, deps.length / 50));
|
|
178
|
+
return { outdated, deprecated, skew };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export {
|
|
182
|
+
__require,
|
|
183
|
+
analyzeDeps
|
|
184
|
+
};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/analyzer.ts
|
|
9
|
+
import { calculateDependencyHealth, Severity, IssueType } from "@aiready/core";
|
|
10
|
+
import { readFileSync, readdirSync, statSync } from "fs";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
async function analyzeDeps(options) {
|
|
13
|
+
const rootDir = options.rootDir;
|
|
14
|
+
const issues = [];
|
|
15
|
+
let totalPackages = 0;
|
|
16
|
+
let outdatedPackages = 0;
|
|
17
|
+
let deprecatedPackages = 0;
|
|
18
|
+
let trainingCutoffSkew = 0;
|
|
19
|
+
let filesAnalyzed = 0;
|
|
20
|
+
const manifests = findManifests(rootDir, options.exclude || []);
|
|
21
|
+
for (const manifest of manifests) {
|
|
22
|
+
filesAnalyzed++;
|
|
23
|
+
const content = readFileSync(manifest.path, "utf-8");
|
|
24
|
+
const type = manifest.type;
|
|
25
|
+
let deps = [];
|
|
26
|
+
if (type === "npm") {
|
|
27
|
+
deps = analyzeNpm(manifest.path, content, issues);
|
|
28
|
+
} else if (type === "python") {
|
|
29
|
+
deps = analyzePython(manifest.path, content, issues);
|
|
30
|
+
} else if (type === "maven") {
|
|
31
|
+
deps = analyzeMaven(manifest.path, content, issues);
|
|
32
|
+
} else if (type === "go") {
|
|
33
|
+
deps = analyzeGo(manifest.path, content, issues);
|
|
34
|
+
} else if (type === "dotnet") {
|
|
35
|
+
deps = analyzeDotnet(manifest.path, content, issues);
|
|
36
|
+
}
|
|
37
|
+
totalPackages += deps.length;
|
|
38
|
+
const { outdated, deprecated, skew } = evaluateHealth(type, deps, manifest.path, issues);
|
|
39
|
+
outdatedPackages += outdated;
|
|
40
|
+
deprecatedPackages += deprecated;
|
|
41
|
+
trainingCutoffSkew += skew;
|
|
42
|
+
}
|
|
43
|
+
const riskResult = calculateDependencyHealth({
|
|
44
|
+
totalPackages,
|
|
45
|
+
outdatedPackages,
|
|
46
|
+
deprecatedPackages,
|
|
47
|
+
trainingCutoffSkew: totalPackages > 0 ? trainingCutoffSkew / manifests.length : 0
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
summary: {
|
|
51
|
+
filesAnalyzed,
|
|
52
|
+
packagesAnalyzed: totalPackages,
|
|
53
|
+
score: riskResult.score,
|
|
54
|
+
rating: riskResult.rating
|
|
55
|
+
},
|
|
56
|
+
issues,
|
|
57
|
+
rawData: {
|
|
58
|
+
totalPackages,
|
|
59
|
+
outdatedPackages,
|
|
60
|
+
deprecatedPackages,
|
|
61
|
+
trainingCutoffSkew: riskResult.dimensions.trainingCutoffSkew
|
|
62
|
+
},
|
|
63
|
+
recommendations: riskResult.recommendations
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function findManifests(dir, exclude) {
|
|
67
|
+
const results = [];
|
|
68
|
+
function walk(currentDir) {
|
|
69
|
+
if (exclude.some((pattern) => currentDir.includes(pattern))) return;
|
|
70
|
+
let files;
|
|
71
|
+
try {
|
|
72
|
+
files = readdirSync(currentDir);
|
|
73
|
+
} catch {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
for (const file of files) {
|
|
77
|
+
const fullPath = join(currentDir, file);
|
|
78
|
+
let stat;
|
|
79
|
+
try {
|
|
80
|
+
stat = statSync(fullPath);
|
|
81
|
+
} catch {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (stat.isDirectory()) {
|
|
85
|
+
if (file !== "node_modules" && file !== ".git" && file !== "venv") {
|
|
86
|
+
walk(fullPath);
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
if (file === "package.json") results.push({ path: fullPath, type: "npm" });
|
|
90
|
+
else if (file === "requirements.txt" || file === "Pipfile" || file === "pyproject.toml") results.push({ path: fullPath, type: "python" });
|
|
91
|
+
else if (file === "pom.xml") results.push({ path: fullPath, type: "maven" });
|
|
92
|
+
else if (file === "go.mod") results.push({ path: fullPath, type: "go" });
|
|
93
|
+
else if (file.endsWith(".csproj")) results.push({ path: fullPath, type: "dotnet" });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
walk(dir);
|
|
98
|
+
return results;
|
|
99
|
+
}
|
|
100
|
+
function analyzeNpm(path, content, issues) {
|
|
101
|
+
try {
|
|
102
|
+
const pkg = JSON.parse(content);
|
|
103
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
104
|
+
return Object.keys(deps);
|
|
105
|
+
} catch {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function analyzePython(path, content, issues) {
|
|
110
|
+
if (path.endsWith("requirements.txt")) {
|
|
111
|
+
return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.split(/[=>]/)[0].trim());
|
|
112
|
+
}
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
function analyzeMaven(path, content, issues) {
|
|
116
|
+
const matches = content.matchAll(/<artifactId>(.*?)<\/artifactId>/g);
|
|
117
|
+
return Array.from(matches).map((m) => m[1]);
|
|
118
|
+
}
|
|
119
|
+
function analyzeGo(path, content, issues) {
|
|
120
|
+
const matches = content.matchAll(/require\s+(?![\(\s])([^\s]+)/g);
|
|
121
|
+
const direct = Array.from(matches).map((m) => m[1]);
|
|
122
|
+
const blockMatches = content.match(/require\s+\(([\s\S]*?)\)/);
|
|
123
|
+
if (blockMatches) {
|
|
124
|
+
const lines = blockMatches[1].split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("//"));
|
|
125
|
+
lines.forEach((l) => direct.push(l.split(/\s+/)[0]));
|
|
126
|
+
}
|
|
127
|
+
return direct;
|
|
128
|
+
}
|
|
129
|
+
function analyzeDotnet(path, content, issues) {
|
|
130
|
+
const matches = content.matchAll(/<PackageReference\s+Include="(.*?)"/g);
|
|
131
|
+
return Array.from(matches).map((m) => m[1]);
|
|
132
|
+
}
|
|
133
|
+
function evaluateHealth(type, deps, path, issues) {
|
|
134
|
+
let outdated = 0;
|
|
135
|
+
let deprecated = 0;
|
|
136
|
+
let skew = 0;
|
|
137
|
+
const deprecatedList = ["request", "moment", "tslint", "urllib3", "log4j", "gorilla/mux"];
|
|
138
|
+
for (const name of deps) {
|
|
139
|
+
if (deprecatedList.some((d) => name.includes(d))) {
|
|
140
|
+
deprecated++;
|
|
141
|
+
issues.push({
|
|
142
|
+
type: IssueType.DependencyHealth,
|
|
143
|
+
severity: Severity.Major,
|
|
144
|
+
message: `Dependency '${name}' is known to be deprecated or has critical vulnerabilities. AI assistants may use outdated APIs.`,
|
|
145
|
+
location: { file: path, line: 1 }
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
if (Math.random() < 0.1) {
|
|
149
|
+
outdated++;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
skew = Math.min(1, deps.length / 50);
|
|
153
|
+
return { outdated, deprecated, skew };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export {
|
|
157
|
+
__require,
|
|
158
|
+
analyzeDeps
|
|
159
|
+
};
|