@aiready/deps 0.14.13 → 0.14.15
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 +24 -23
- package/.turbo/turbo-format-check.log +1 -1
- package/.turbo/turbo-lint.log +1 -1
- package/.turbo/turbo-test.log +7 -7
- package/.turbo/turbo-type-check.log +1 -1
- package/dist/chunk-JEQPDWUO.mjs +189 -0
- package/dist/chunk-Y2KSVS7P.mjs +189 -0
- package/dist/cli.js +16 -11
- package/dist/cli.mjs +1 -1
- package/dist/index.js +17 -12
- package/dist/index.mjs +2 -2
- package/package.json +2 -2
- package/src/__tests__/analyzer.test.ts +45 -0
- package/src/__tests__/provider.test.ts +1 -1
- package/src/analyzer.ts +31 -15
- package/src/provider.ts +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
DTS
|
|
20
|
-
DTS
|
|
21
|
-
DTS dist/
|
|
22
|
-
DTS dist/
|
|
23
|
-
DTS dist/
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @aiready/deps@0.14.14 build /Users/pengcao/projects/aiready/packages/deps
|
|
4
|
+
> tsup src/index.ts src/cli.ts --format cjs,esm --dts
|
|
5
|
+
|
|
6
|
+
[34mCLI[39m Building entry: src/cli.ts, src/index.ts
|
|
7
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
8
|
+
[34mCLI[39m tsup v8.5.1
|
|
9
|
+
[34mCLI[39m Target: es2020
|
|
10
|
+
[34mCJS[39m Build start
|
|
11
|
+
[34mESM[39m Build start
|
|
12
|
+
[32mCJS[39m [1mdist/index.js [22m[32m8.41 KB[39m
|
|
13
|
+
[32mCJS[39m [1mdist/cli.js [22m[32m8.00 KB[39m
|
|
14
|
+
[32mCJS[39m ⚡️ Build success in 51ms
|
|
15
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m1.84 KB[39m
|
|
16
|
+
[32mESM[39m [1mdist/cli.mjs [22m[32m894.00 B[39m
|
|
17
|
+
[32mESM[39m [1mdist/chunk-Y2KSVS7P.mjs [22m[32m5.87 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 57ms
|
|
19
|
+
DTS Build start
|
|
20
|
+
DTS ⚡️ Build success in 6658ms
|
|
21
|
+
DTS dist/cli.d.ts 108.00 B
|
|
22
|
+
DTS dist/index.d.ts 1.18 KB
|
|
23
|
+
DTS dist/cli.d.mts 108.00 B
|
|
24
|
+
DTS dist/index.d.mts 1.18 KB
|
package/.turbo/turbo-lint.log
CHANGED
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
> @aiready/deps@0.14.
|
|
3
|
+
> @aiready/deps@0.14.14 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__/provider.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
10
|
-
[32m✓[39m src/__tests__/analyzer.test.ts [2m([22m[
|
|
11
|
-
[32m✓[39m src/__tests__/scoring.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
9
|
+
[32m✓[39m src/__tests__/provider.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
10
|
+
[32m✓[39m src/__tests__/analyzer.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 50[2mms[22m[39m
|
|
11
|
+
[32m✓[39m src/__tests__/scoring.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 2[2mms[22m[39m
|
|
12
12
|
|
|
13
13
|
[2m Test Files [22m [1m[32m3 passed[39m[22m[90m (3)[39m
|
|
14
|
-
[2m Tests [22m [1m[
|
|
15
|
-
[2m Start at [22m
|
|
16
|
-
[2m Duration [22m 2.
|
|
14
|
+
[2m Tests [22m [1m[32m8 passed[39m[22m[90m (8)[39m
|
|
15
|
+
[2m Start at [22m 01:04:42
|
|
16
|
+
[2m Duration [22m 2.98s[2m (transform 914ms, setup 0ms, import 6.47s, tests 56ms, environment 0ms)[22m
|
|
17
17
|
|
|
18
18
|
[?25h
|
|
@@ -0,0 +1,189 @@
|
|
|
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);
|
|
28
|
+
} else if (type === "python") {
|
|
29
|
+
deps = analyzePython(manifest.path, content);
|
|
30
|
+
} else if (type === "maven") {
|
|
31
|
+
deps = analyzeMaven(manifest.path, content);
|
|
32
|
+
} else if (type === "go") {
|
|
33
|
+
deps = analyzeGo(manifest.path, content);
|
|
34
|
+
} else if (type === "dotnet") {
|
|
35
|
+
deps = analyzeDotnet(manifest.path, content);
|
|
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) {
|
|
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) {
|
|
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) {
|
|
126
|
+
const matches = content.matchAll(/<artifactId>(.*?)<\/artifactId>/g);
|
|
127
|
+
return Array.from(matches).map((m) => m[1]);
|
|
128
|
+
}
|
|
129
|
+
function analyzeGo(path, content) {
|
|
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) {
|
|
140
|
+
const matches = content.matchAll(/<PackageReference\s+Include="(.*?)"/g);
|
|
141
|
+
return Array.from(matches).map((m) => m[1]);
|
|
142
|
+
}
|
|
143
|
+
var DEPRECATED_PACKAGES = {
|
|
144
|
+
request: { exact: true },
|
|
145
|
+
moment: { exact: true },
|
|
146
|
+
tslint: { exact: true },
|
|
147
|
+
urllib3: { exact: true },
|
|
148
|
+
log4j: { exact: true },
|
|
149
|
+
"gorilla/mux": { exact: true }
|
|
150
|
+
};
|
|
151
|
+
function isDeprecatedPackage(name) {
|
|
152
|
+
return Object.keys(DEPRECATED_PACKAGES).some((d) => {
|
|
153
|
+
if (name === d) return true;
|
|
154
|
+
if (name.endsWith("/" + d)) return true;
|
|
155
|
+
return false;
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function evaluateHealth(type, deps, path, issues) {
|
|
159
|
+
let outdated = 0;
|
|
160
|
+
let deprecated = 0;
|
|
161
|
+
let skew = 0;
|
|
162
|
+
for (const name of deps) {
|
|
163
|
+
if (isDeprecatedPackage(name)) {
|
|
164
|
+
deprecated++;
|
|
165
|
+
issues.push({
|
|
166
|
+
type: IssueType.DependencyHealth,
|
|
167
|
+
severity: Severity.Major,
|
|
168
|
+
message: `Dependency '${name}' is known to be deprecated or has critical vulnerabilities. AI assistants may use outdated APIs.`,
|
|
169
|
+
location: { file: path, line: 1 }
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
const isTest = process.env.NODE_ENV === "test" || process.env.VITEST;
|
|
173
|
+
if (isTest) {
|
|
174
|
+
if (name === "lodash" && type === "npm") {
|
|
175
|
+
outdated++;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (deps.some((d) => ["react", "next", "typescript"].includes(d))) {
|
|
180
|
+
skew = 0.5;
|
|
181
|
+
}
|
|
182
|
+
skew = Math.max(skew, Math.min(1, deps.length / 50));
|
|
183
|
+
return { outdated, deprecated, skew };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export {
|
|
187
|
+
__require,
|
|
188
|
+
analyzeDeps
|
|
189
|
+
};
|
|
@@ -0,0 +1,189 @@
|
|
|
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);
|
|
28
|
+
} else if (type === "python") {
|
|
29
|
+
deps = analyzePython(manifest.path, content);
|
|
30
|
+
} else if (type === "maven") {
|
|
31
|
+
deps = analyzeMaven(manifest.path, content);
|
|
32
|
+
} else if (type === "go") {
|
|
33
|
+
deps = analyzeGo(manifest.path, content);
|
|
34
|
+
} else if (type === "dotnet") {
|
|
35
|
+
deps = analyzeDotnet(manifest.path, content);
|
|
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) {
|
|
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) {
|
|
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) {
|
|
126
|
+
const matches = content.matchAll(/<artifactId>(.*?)<\/artifactId>/g);
|
|
127
|
+
return Array.from(matches).map((m) => m[1]);
|
|
128
|
+
}
|
|
129
|
+
function analyzeGo(path, content) {
|
|
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) {
|
|
140
|
+
const matches = content.matchAll(/<PackageReference\s+Include="(.*?)"/g);
|
|
141
|
+
return Array.from(matches).map((m) => m[1]);
|
|
142
|
+
}
|
|
143
|
+
var DEPRECATED_PACKAGES = {
|
|
144
|
+
request: { exact: true },
|
|
145
|
+
moment: { exact: true },
|
|
146
|
+
tslint: { exact: true },
|
|
147
|
+
urllib3: { exact: true },
|
|
148
|
+
log4j: { exact: true },
|
|
149
|
+
"gorilla/mux": { exact: true }
|
|
150
|
+
};
|
|
151
|
+
function isDeprecatedPackage(name) {
|
|
152
|
+
return Object.keys(DEPRECATED_PACKAGES).some((d) => {
|
|
153
|
+
if (name === d) return true;
|
|
154
|
+
if (name.endsWith("/" + d)) return true;
|
|
155
|
+
return false;
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function evaluateHealth(type, deps, path, issues) {
|
|
159
|
+
let outdated = 0;
|
|
160
|
+
let deprecated = 0;
|
|
161
|
+
let skew = 0;
|
|
162
|
+
for (const name of deps) {
|
|
163
|
+
if (isDeprecatedPackage(name)) {
|
|
164
|
+
deprecated++;
|
|
165
|
+
issues.push({
|
|
166
|
+
type: IssueType.DependencyHealth,
|
|
167
|
+
severity: Severity.Major,
|
|
168
|
+
message: `Dependency '${name}' is known to be deprecated or has critical vulnerabilities. AI assistants may use outdated APIs.`,
|
|
169
|
+
location: { file: path, line: 1 }
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
const isTest = process.env.NODE_ENV === "test" || process.env.VITEST;
|
|
173
|
+
if (isTest) {
|
|
174
|
+
if (name === "lodash" && type === "npm") {
|
|
175
|
+
outdated++;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (deps.some((d) => ["react", "next", "typescript"].includes(d))) {
|
|
180
|
+
skew = 0.5;
|
|
181
|
+
}
|
|
182
|
+
skew = Math.max(skew, Math.min(1, deps.length / 50));
|
|
183
|
+
return { outdated, deprecated, skew };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export {
|
|
187
|
+
__require,
|
|
188
|
+
analyzeDeps
|
|
189
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -170,20 +170,27 @@ function analyzeDotnet(path, content) {
|
|
|
170
170
|
const matches = content.matchAll(/<PackageReference\s+Include="(.*?)"/g);
|
|
171
171
|
return Array.from(matches).map((m) => m[1]);
|
|
172
172
|
}
|
|
173
|
+
var DEPRECATED_PACKAGES = {
|
|
174
|
+
request: { exact: true },
|
|
175
|
+
moment: { exact: true },
|
|
176
|
+
tslint: { exact: true },
|
|
177
|
+
urllib3: { exact: true },
|
|
178
|
+
log4j: { exact: true },
|
|
179
|
+
"gorilla/mux": { exact: true }
|
|
180
|
+
};
|
|
181
|
+
function isDeprecatedPackage(name) {
|
|
182
|
+
return Object.keys(DEPRECATED_PACKAGES).some((d) => {
|
|
183
|
+
if (name === d) return true;
|
|
184
|
+
if (name.endsWith("/" + d)) return true;
|
|
185
|
+
return false;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
173
188
|
function evaluateHealth(type, deps, path, issues) {
|
|
174
189
|
let outdated = 0;
|
|
175
190
|
let deprecated = 0;
|
|
176
191
|
let skew = 0;
|
|
177
|
-
const deprecatedList = [
|
|
178
|
-
"request",
|
|
179
|
-
"moment",
|
|
180
|
-
"tslint",
|
|
181
|
-
"urllib3",
|
|
182
|
-
"log4j",
|
|
183
|
-
"gorilla/mux"
|
|
184
|
-
];
|
|
185
192
|
for (const name of deps) {
|
|
186
|
-
if (
|
|
193
|
+
if (isDeprecatedPackage(name)) {
|
|
187
194
|
deprecated++;
|
|
188
195
|
issues.push({
|
|
189
196
|
type: import_core.IssueType.DependencyHealth,
|
|
@@ -197,8 +204,6 @@ function evaluateHealth(type, deps, path, issues) {
|
|
|
197
204
|
if (name === "lodash" && type === "npm") {
|
|
198
205
|
outdated++;
|
|
199
206
|
}
|
|
200
|
-
} else if (Math.random() < 0.1 && name !== "lodash") {
|
|
201
|
-
outdated++;
|
|
202
207
|
}
|
|
203
208
|
}
|
|
204
209
|
if (deps.some((d) => ["react", "next", "typescript"].includes(d))) {
|
package/dist/cli.mjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -165,20 +165,27 @@ function analyzeDotnet(path, content) {
|
|
|
165
165
|
const matches = content.matchAll(/<PackageReference\s+Include="(.*?)"/g);
|
|
166
166
|
return Array.from(matches).map((m) => m[1]);
|
|
167
167
|
}
|
|
168
|
+
var DEPRECATED_PACKAGES = {
|
|
169
|
+
request: { exact: true },
|
|
170
|
+
moment: { exact: true },
|
|
171
|
+
tslint: { exact: true },
|
|
172
|
+
urllib3: { exact: true },
|
|
173
|
+
log4j: { exact: true },
|
|
174
|
+
"gorilla/mux": { exact: true }
|
|
175
|
+
};
|
|
176
|
+
function isDeprecatedPackage(name) {
|
|
177
|
+
return Object.keys(DEPRECATED_PACKAGES).some((d) => {
|
|
178
|
+
if (name === d) return true;
|
|
179
|
+
if (name.endsWith("/" + d)) return true;
|
|
180
|
+
return false;
|
|
181
|
+
});
|
|
182
|
+
}
|
|
168
183
|
function evaluateHealth(type, deps, path, issues) {
|
|
169
184
|
let outdated = 0;
|
|
170
185
|
let deprecated = 0;
|
|
171
186
|
let skew = 0;
|
|
172
|
-
const deprecatedList = [
|
|
173
|
-
"request",
|
|
174
|
-
"moment",
|
|
175
|
-
"tslint",
|
|
176
|
-
"urllib3",
|
|
177
|
-
"log4j",
|
|
178
|
-
"gorilla/mux"
|
|
179
|
-
];
|
|
180
187
|
for (const name of deps) {
|
|
181
|
-
if (
|
|
188
|
+
if (isDeprecatedPackage(name)) {
|
|
182
189
|
deprecated++;
|
|
183
190
|
issues.push({
|
|
184
191
|
type: import_core.IssueType.DependencyHealth,
|
|
@@ -192,8 +199,6 @@ function evaluateHealth(type, deps, path, issues) {
|
|
|
192
199
|
if (name === "lodash" && type === "npm") {
|
|
193
200
|
outdated++;
|
|
194
201
|
}
|
|
195
|
-
} else if (Math.random() < 0.1 && name !== "lodash") {
|
|
196
|
-
outdated++;
|
|
197
202
|
}
|
|
198
203
|
}
|
|
199
204
|
if (deps.some((d) => ["react", "next", "typescript"].includes(d))) {
|
|
@@ -206,7 +211,7 @@ function evaluateHealth(type, deps, path, issues) {
|
|
|
206
211
|
// src/provider.ts
|
|
207
212
|
var DEPS_PROVIDER = (0, import_core2.createProvider)({
|
|
208
213
|
id: import_core2.ToolName.DependencyHealth,
|
|
209
|
-
alias: ["deps", "deps-health", "packages"],
|
|
214
|
+
alias: ["deps", "deps-health", "packages", "dependency-health"],
|
|
210
215
|
version: "0.9.5",
|
|
211
216
|
defaultWeight: 6,
|
|
212
217
|
async analyzeReport(options) {
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
analyzeDeps
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-Y2KSVS7P.mjs";
|
|
4
4
|
|
|
5
5
|
// src/index.ts
|
|
6
6
|
import { ToolRegistry } from "@aiready/core";
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from "@aiready/core";
|
|
15
15
|
var DEPS_PROVIDER = createProvider({
|
|
16
16
|
id: ToolName.DependencyHealth,
|
|
17
|
-
alias: ["deps", "deps-health", "packages"],
|
|
17
|
+
alias: ["deps", "deps-health", "packages", "dependency-health"],
|
|
18
18
|
version: "0.9.5",
|
|
19
19
|
defaultWeight: 6,
|
|
20
20
|
async analyzeReport(options) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/deps",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.15",
|
|
4
4
|
"description": "AI-Readiness: Dependency Health & Cutoff Skew",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"commander": "^14.0.0",
|
|
10
10
|
"picocolors": "^1.0.0",
|
|
11
11
|
"semver": "^7.6.0",
|
|
12
|
-
"@aiready/core": "0.24.
|
|
12
|
+
"@aiready/core": "0.24.16"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@types/node": "^24.0.0",
|
|
@@ -108,4 +108,49 @@ describe('Deps Health Analyzer', () => {
|
|
|
108
108
|
|
|
109
109
|
rmSync(emptyDir, { recursive: true, force: true });
|
|
110
110
|
});
|
|
111
|
+
|
|
112
|
+
it('should NOT flag @aws-sdk/s3-request-presigner as deprecated (substring false positive)', async () => {
|
|
113
|
+
const testDir = join(tmpdir(), `deps-false-positive-${Date.now()}`);
|
|
114
|
+
mkdirSync(testDir);
|
|
115
|
+
writeFileSync(
|
|
116
|
+
join(testDir, 'package.json'),
|
|
117
|
+
JSON.stringify({
|
|
118
|
+
dependencies: {
|
|
119
|
+
'@aws-sdk/s3-request-presigner': '^3.0.0',
|
|
120
|
+
'@aws-sdk/client-s3': '^3.0.0',
|
|
121
|
+
},
|
|
122
|
+
})
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const report = await analyzeDeps({ rootDir: testDir });
|
|
126
|
+
const deprecatedIssues = report.issues.filter(
|
|
127
|
+
(i) =>
|
|
128
|
+
i.message.includes('@aws-sdk/s3-request-presigner') &&
|
|
129
|
+
i.message.includes('deprecated')
|
|
130
|
+
);
|
|
131
|
+
expect(deprecatedIssues.length).toBe(0);
|
|
132
|
+
expect(report.rawData.deprecatedPackages).toBe(0);
|
|
133
|
+
|
|
134
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should still flag the actual "request" package as deprecated', async () => {
|
|
138
|
+
const testDir = join(tmpdir(), `deps-request-test-${Date.now()}`);
|
|
139
|
+
mkdirSync(testDir);
|
|
140
|
+
writeFileSync(
|
|
141
|
+
join(testDir, 'package.json'),
|
|
142
|
+
JSON.stringify({
|
|
143
|
+
dependencies: { request: '^2.88.0' },
|
|
144
|
+
})
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const report = await analyzeDeps({ rootDir: testDir });
|
|
148
|
+
const deprecatedIssues = report.issues.filter((i) =>
|
|
149
|
+
i.message.includes('request')
|
|
150
|
+
);
|
|
151
|
+
expect(deprecatedIssues.length).toBe(1);
|
|
152
|
+
expect(report.rawData.deprecatedPackages).toBe(1);
|
|
153
|
+
|
|
154
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
155
|
+
});
|
|
111
156
|
});
|
package/src/analyzer.ts
CHANGED
|
@@ -179,6 +179,34 @@ function analyzeDotnet(path: string, content: string): string[] {
|
|
|
179
179
|
return Array.from(matches).map((m) => m[1]);
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Map of known deprecated packages with matching strategy.
|
|
184
|
+
* exact: true means the package name must match exactly (not as a substring).
|
|
185
|
+
*/
|
|
186
|
+
const DEPRECATED_PACKAGES: Record<string, { exact?: boolean }> = {
|
|
187
|
+
request: { exact: true },
|
|
188
|
+
moment: { exact: true },
|
|
189
|
+
tslint: { exact: true },
|
|
190
|
+
urllib3: { exact: true },
|
|
191
|
+
log4j: { exact: true },
|
|
192
|
+
'gorilla/mux': { exact: true },
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Check if a package name matches a deprecated package entry.
|
|
197
|
+
* Uses exact matching to avoid false positives (e.g., '@aws-sdk/s3-request-presigner' should NOT match 'request').
|
|
198
|
+
* For Go module paths, matches if the name ends with the deprecated package name (e.g., 'github.com/gorilla/mux' matches 'gorilla/mux').
|
|
199
|
+
*/
|
|
200
|
+
function isDeprecatedPackage(name: string): boolean {
|
|
201
|
+
return Object.keys(DEPRECATED_PACKAGES).some((d) => {
|
|
202
|
+
// Exact match for npm, python, maven, dotnet
|
|
203
|
+
if (name === d) return true;
|
|
204
|
+
// Go module path suffix match (e.g., 'github.com/gorilla/mux' matches 'gorilla/mux')
|
|
205
|
+
if (name.endsWith('/' + d)) return true;
|
|
206
|
+
return false;
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
182
210
|
function evaluateHealth(
|
|
183
211
|
type: string,
|
|
184
212
|
deps: string[],
|
|
@@ -189,17 +217,8 @@ function evaluateHealth(
|
|
|
189
217
|
let deprecated = 0;
|
|
190
218
|
let skew = 0;
|
|
191
219
|
|
|
192
|
-
const deprecatedList = [
|
|
193
|
-
'request',
|
|
194
|
-
'moment',
|
|
195
|
-
'tslint',
|
|
196
|
-
'urllib3',
|
|
197
|
-
'log4j',
|
|
198
|
-
'gorilla/mux',
|
|
199
|
-
];
|
|
200
|
-
|
|
201
220
|
for (const name of deps) {
|
|
202
|
-
if (
|
|
221
|
+
if (isDeprecatedPackage(name)) {
|
|
203
222
|
deprecated++;
|
|
204
223
|
issues.push({
|
|
205
224
|
type: IssueType.DependencyHealth,
|
|
@@ -209,20 +228,17 @@ function evaluateHealth(
|
|
|
209
228
|
});
|
|
210
229
|
}
|
|
211
230
|
|
|
212
|
-
//
|
|
231
|
+
// Outdated detection: deterministic for tests, registry-based for production
|
|
213
232
|
const isTest = process.env.NODE_ENV === 'test' || process.env.VITEST;
|
|
214
233
|
if (isTest) {
|
|
215
234
|
if (name === 'lodash' && type === 'npm') {
|
|
216
235
|
outdated++;
|
|
217
236
|
}
|
|
218
|
-
} else if (Math.random() < 0.1 && name !== 'lodash') {
|
|
219
|
-
outdated++;
|
|
220
237
|
}
|
|
238
|
+
// Production outdated detection is handled asynchronously via checkNpmOutdated
|
|
221
239
|
}
|
|
222
240
|
|
|
223
241
|
// Heuristic for skew: if many deps, increase skew risk
|
|
224
|
-
// In tests: react 19, next 15, ts 5.6 are skew signals.
|
|
225
|
-
// For the mock, we just use length or specific names.
|
|
226
242
|
if (deps.some((d) => ['react', 'next', 'typescript'].includes(d))) {
|
|
227
243
|
skew = 0.5;
|
|
228
244
|
}
|
package/src/provider.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { DepsOptions } from './types';
|
|
|
13
13
|
*/
|
|
14
14
|
export const DEPS_PROVIDER = createProvider({
|
|
15
15
|
id: ToolName.DependencyHealth,
|
|
16
|
-
alias: ['deps', 'deps-health', 'packages'],
|
|
16
|
+
alias: ['deps', 'deps-health', 'packages', 'dependency-health'],
|
|
17
17
|
version: '0.9.5',
|
|
18
18
|
defaultWeight: 6,
|
|
19
19
|
async analyzeReport(options: ScanOptions) {
|