speexjs-core 0.7.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 +117 -0
- package/CONTRIBUTING.md +55 -0
- package/PUBLISH.md +45 -0
- package/README.md +174 -0
- package/ROADMAP.md +72 -0
- package/SECURITY.md +35 -0
- package/SUMMARY.md +321 -0
- package/dist/async/index.d.ts +232 -0
- package/dist/async/index.js +366 -0
- package/dist/async/index.js.map +1 -0
- package/dist/collection/index.d.ts +230 -0
- package/dist/collection/index.js +375 -0
- package/dist/collection/index.js.map +1 -0
- package/dist/color/index.d.ts +128 -0
- package/dist/color/index.js +167 -0
- package/dist/color/index.js.map +1 -0
- package/dist/core/index.d.ts +119 -0
- package/dist/core/index.js +324 -0
- package/dist/core/index.js.map +1 -0
- package/dist/crypto/index.d.ts +84 -0
- package/dist/crypto/index.js +144 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/date/index.d.ts +588 -0
- package/dist/date/index.js +737 -0
- package/dist/date/index.js.map +1 -0
- package/dist/dep-exray/analyzer/index.d.ts +7 -0
- package/dist/dep-exray/analyzer/index.js +68 -0
- package/dist/dep-exray/analyzer/index.js.map +1 -0
- package/dist/dep-exray/cli.d.ts +1 -0
- package/dist/dep-exray/cli.js +441 -0
- package/dist/dep-exray/cli.js.map +1 -0
- package/dist/dep-exray/index.d.ts +5 -0
- package/dist/dep-exray/index.js +454 -0
- package/dist/dep-exray/index.js.map +1 -0
- package/dist/dep-exray/known-mappings.d.ts +17 -0
- package/dist/dep-exray/known-mappings.js +122 -0
- package/dist/dep-exray/known-mappings.js.map +1 -0
- package/dist/dep-exray/reporter/index.d.ts +5 -0
- package/dist/dep-exray/reporter/index.js +89 -0
- package/dist/dep-exray/reporter/index.js.map +1 -0
- package/dist/dep-exray/scanner/index.d.ts +5 -0
- package/dist/dep-exray/scanner/index.js +299 -0
- package/dist/dep-exray/scanner/index.js.map +1 -0
- package/dist/dep-exray/types.d.ts +38 -0
- package/dist/dep-exray/types.js +1 -0
- package/dist/dep-exray/types.js.map +1 -0
- package/dist/error/index.d.ts +148 -0
- package/dist/error/index.js +115 -0
- package/dist/error/index.js.map +1 -0
- package/dist/index-BgG21uJC.d.ts +166 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +4378 -0
- package/dist/index.js.map +1 -0
- package/dist/io/index.d.ts +39 -0
- package/dist/io/index.js +111 -0
- package/dist/io/index.js.map +1 -0
- package/dist/logger/index.d.ts +1 -0
- package/dist/logger/index.js +214 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/logger/transports.d.ts +1 -0
- package/dist/logger/transports.js +122 -0
- package/dist/logger/transports.js.map +1 -0
- package/dist/math/index.d.ts +362 -0
- package/dist/math/index.js +372 -0
- package/dist/math/index.js.map +1 -0
- package/dist/path/index.d.ts +81 -0
- package/dist/path/index.js +134 -0
- package/dist/path/index.js.map +1 -0
- package/dist/string/index.d.ts +234 -0
- package/dist/string/index.js +411 -0
- package/dist/string/index.js.map +1 -0
- package/dist/type/index.d.ts +85 -0
- package/dist/type/index.js +107 -0
- package/dist/type/index.js.map +1 -0
- package/dist/validation/index.d.ts +203 -0
- package/dist/validation/index.js +402 -0
- package/dist/validation/index.js.map +1 -0
- package/package.json +172 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
// src/dep-exray/scanner/index.ts
|
|
2
|
+
import { readFileSync, readdirSync, existsSync } from "fs";
|
|
3
|
+
import { join, basename } from "path";
|
|
4
|
+
|
|
5
|
+
// src/dep-exray/known-mappings.ts
|
|
6
|
+
var KNOWN_MAPPINGS = [
|
|
7
|
+
{
|
|
8
|
+
name: "lodash",
|
|
9
|
+
size: "4.2 MB",
|
|
10
|
+
replacement: "jscore-core",
|
|
11
|
+
confidence: "high",
|
|
12
|
+
autoPrReady: true,
|
|
13
|
+
reason: "Most lodash functions have direct replacements in jscore-core with 99% API compatibility",
|
|
14
|
+
detectionPattern: `from ['"]lodash['"]|require\\(['"]lodash['"]\\)`
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: "moment",
|
|
18
|
+
size: "2.5 MB",
|
|
19
|
+
replacement: "jscore-core/date",
|
|
20
|
+
confidence: "high",
|
|
21
|
+
autoPrReady: true,
|
|
22
|
+
reason: "date utilities in jscore-core cover 95% of common moment use cases",
|
|
23
|
+
detectionPattern: `from ['"]moment['"]|require\\(['"]moment['"]\\)`
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "date-fns",
|
|
27
|
+
size: "1.2 MB (tree-shaked ~50KB)",
|
|
28
|
+
replacement: "jscore-core/date",
|
|
29
|
+
confidence: "medium",
|
|
30
|
+
autoPrReady: false,
|
|
31
|
+
reason: "Partially overlapping \u2014 jscore-core covers basic date ops but not all locale support",
|
|
32
|
+
detectionPattern: `from ['"]date-fns['"]|require\\(['"]date-fns['"]\\)`
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "axios",
|
|
36
|
+
size: "1.6 MB",
|
|
37
|
+
replacement: "native fetch + jscore-core/async/retry",
|
|
38
|
+
confidence: "medium",
|
|
39
|
+
autoPrReady: false,
|
|
40
|
+
reason: "Native fetch covers most use cases; needs manual review for interceptors",
|
|
41
|
+
detectionPattern: `from ['"]axios['"]|require\\(['"]axios['"]\\)`
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "uuid",
|
|
45
|
+
size: "30 KB",
|
|
46
|
+
replacement: "crypto.randomUUID() (native)",
|
|
47
|
+
confidence: "high",
|
|
48
|
+
autoPrReady: true,
|
|
49
|
+
reason: "crypto.randomUUID() is available in all modern Node.js and browsers",
|
|
50
|
+
detectionPattern: `from ['"]uuid['"]|require\\(['"]uuid['"]\\)`
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "deepmerge",
|
|
54
|
+
size: "15 KB",
|
|
55
|
+
replacement: "jscore-core",
|
|
56
|
+
confidence: "high",
|
|
57
|
+
autoPrReady: true,
|
|
58
|
+
reason: "jscore-core provides deepMerge out of the box",
|
|
59
|
+
detectionPattern: `from ['"]deepmerge['"]|require\\(['"]deepmerge['"]\\)`
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "lodash.merge",
|
|
63
|
+
size: "25 KB",
|
|
64
|
+
replacement: "jscore-core",
|
|
65
|
+
confidence: "high",
|
|
66
|
+
autoPrReady: true,
|
|
67
|
+
reason: "jscore-core provides deepMerge out of the box",
|
|
68
|
+
detectionPattern: `from ['"]lodash\\.(merge|clone|pick|omit|get|set)['"]`
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: "chalk",
|
|
72
|
+
size: "45 KB",
|
|
73
|
+
replacement: "picocolors",
|
|
74
|
+
confidence: "medium",
|
|
75
|
+
autoPrReady: false,
|
|
76
|
+
reason: "picocolors is 3KB vs chalk's 45KB with same API",
|
|
77
|
+
detectionPattern: `from ['"]chalk['"]|require\\(['"]chalk['"]\\)`
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "nanoid",
|
|
81
|
+
size: "8 KB",
|
|
82
|
+
replacement: "jscore-core/string (nanoid)",
|
|
83
|
+
confidence: "high",
|
|
84
|
+
autoPrReady: true,
|
|
85
|
+
reason: "jscore-core provides nanoid with same API",
|
|
86
|
+
detectionPattern: `from ['"]nanoid['"]|require\\(['"]nanoid['"]\\)`
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "dayjs",
|
|
90
|
+
size: "50 KB",
|
|
91
|
+
replacement: "jscore-core/date",
|
|
92
|
+
confidence: "medium",
|
|
93
|
+
autoPrReady: false,
|
|
94
|
+
reason: "Partially overlapping \u2014 covers basics but not all plugins",
|
|
95
|
+
detectionPattern: `from ['"]dayjs['"]|require\\(['"]dayjs['"]\\)`
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "clsx",
|
|
99
|
+
size: "5 KB",
|
|
100
|
+
replacement: "native template literals",
|
|
101
|
+
confidence: "high",
|
|
102
|
+
autoPrReady: true,
|
|
103
|
+
reason: "Can be replaced with simple template literal conditional pattern",
|
|
104
|
+
detectionPattern: `from ['"]clsx['"]|require\\(['"]clsx['"]\\)`
|
|
105
|
+
}
|
|
106
|
+
];
|
|
107
|
+
var KNOWN_CVES = {
|
|
108
|
+
"ansi-regex": [
|
|
109
|
+
{ cve: "CVE-2021-3807", severity: "high", fix: "Update to ansi-regex@6.0.1 or later" }
|
|
110
|
+
],
|
|
111
|
+
"semver": [
|
|
112
|
+
{ cve: "CVE-2022-25883", severity: "medium", fix: "Update to semver@7.5.2 or later" }
|
|
113
|
+
],
|
|
114
|
+
"json5": [
|
|
115
|
+
{ cve: "CVE-2022-46175", severity: "high", fix: "Update to json5@2.2.3 or later" }
|
|
116
|
+
],
|
|
117
|
+
"lodash": [
|
|
118
|
+
{ cve: "CVE-2020-28502", severity: "high", fix: "Update to lodash@4.17.21 or later" },
|
|
119
|
+
{ cve: "CVE-2020-8203", severity: "medium", fix: "Update to lodash@4.17.21 or later" }
|
|
120
|
+
]
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// src/dep-exray/scanner/index.ts
|
|
124
|
+
function parsePackageJson(path) {
|
|
125
|
+
const raw = readFileSync(path, "utf-8");
|
|
126
|
+
const json = JSON.parse(raw);
|
|
127
|
+
return {
|
|
128
|
+
name: json.name ?? basename(join(path, "..")),
|
|
129
|
+
dependencies: json.dependencies ?? {},
|
|
130
|
+
devDependencies: json.devDependencies ?? {}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function parseLockfile(projectPath) {
|
|
134
|
+
const lockPath = join(projectPath, "package-lock.json");
|
|
135
|
+
if (!existsSync(lockPath)) return null;
|
|
136
|
+
try {
|
|
137
|
+
const raw = readFileSync(lockPath, "utf-8");
|
|
138
|
+
const json = JSON.parse(raw);
|
|
139
|
+
const packages = {};
|
|
140
|
+
if (json.packages) {
|
|
141
|
+
for (const [key, val] of Object.entries(json.packages)) {
|
|
142
|
+
if (key) {
|
|
143
|
+
packages[key] = val;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (json.dependencies && Object.keys(packages).length === 0) {
|
|
148
|
+
for (const [key, val] of Object.entries(json.dependencies)) {
|
|
149
|
+
packages[key] = { version: val.version, dependencies: val.requires };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return { packages };
|
|
153
|
+
} catch {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function detectImportInFile(filePath, regex) {
|
|
158
|
+
try {
|
|
159
|
+
const content = readFileSync(filePath, "utf-8");
|
|
160
|
+
return regex.test(content);
|
|
161
|
+
} catch {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function detectImportsInSrc(projectPath, mapping) {
|
|
166
|
+
const regex = new RegExp(mapping.detectionPattern);
|
|
167
|
+
const srcDir = join(projectPath, "src");
|
|
168
|
+
if (!existsSync(srcDir)) return false;
|
|
169
|
+
try {
|
|
170
|
+
const files = collectSourceFiles(srcDir);
|
|
171
|
+
for (const file of files) {
|
|
172
|
+
if (detectImportInFile(file, regex)) return true;
|
|
173
|
+
}
|
|
174
|
+
} catch {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
function collectSourceFiles(dir) {
|
|
180
|
+
const results = [];
|
|
181
|
+
try {
|
|
182
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
183
|
+
for (const entry of entries) {
|
|
184
|
+
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git" || entry.name === "coverage" || entry.name === ".tsup") {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const full = join(dir, entry.name);
|
|
188
|
+
if (entry.isDirectory()) {
|
|
189
|
+
results.push(...collectSourceFiles(full));
|
|
190
|
+
} else if (entry.isFile()) {
|
|
191
|
+
const ext = entry.name.split(".").pop();
|
|
192
|
+
if (ext === "ts" || ext === "tsx" || ext === "js" || ext === "jsx" || ext === "mjs" || ext === "cjs") {
|
|
193
|
+
results.push(full);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
} catch {
|
|
198
|
+
}
|
|
199
|
+
return results;
|
|
200
|
+
}
|
|
201
|
+
function estimateTransitiveCount(lockfile, directNames) {
|
|
202
|
+
if (!lockfile) return 0;
|
|
203
|
+
let count = 0;
|
|
204
|
+
for (const key of Object.keys(lockfile.packages)) {
|
|
205
|
+
if (!key || key === "") continue;
|
|
206
|
+
const name = key.startsWith("node_modules/") ? key.slice("node_modules/".length) : key;
|
|
207
|
+
const rootName = name.startsWith("@") ? `${name.split("/")[0]}/${name.split("/")[1]}` : name.split("/")[0];
|
|
208
|
+
if (rootName && !directNames.has(rootName)) {
|
|
209
|
+
count++;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return count;
|
|
213
|
+
}
|
|
214
|
+
function parseSize(value) {
|
|
215
|
+
const cleaned = value.replace(/\(.*?\)/g, "").trim();
|
|
216
|
+
const match = cleaned.match(/^([\d.]+)\s*(KB|MB)/i);
|
|
217
|
+
if (!match) return 0;
|
|
218
|
+
const num = Number.parseFloat(match[1]);
|
|
219
|
+
if (!match[2]) return 0;
|
|
220
|
+
if (match[2].toUpperCase() === "MB") return num * 1024;
|
|
221
|
+
return num;
|
|
222
|
+
}
|
|
223
|
+
async function scanProject(config) {
|
|
224
|
+
const projectPath = config.path ?? ".";
|
|
225
|
+
const pkgPath = join(projectPath, "package.json");
|
|
226
|
+
if (!existsSync(pkgPath)) {
|
|
227
|
+
throw new Error(`No package.json found at ${projectPath}. Run dep-exray in a JavaScript/TypeScript project directory.`);
|
|
228
|
+
}
|
|
229
|
+
const pkg = parsePackageJson(pkgPath);
|
|
230
|
+
const lockfile = parseLockfile(projectPath);
|
|
231
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
232
|
+
const directNames = new Set(Object.keys(allDeps));
|
|
233
|
+
const transitiveCount = estimateTransitiveCount(lockfile, directNames);
|
|
234
|
+
const highImpactReplacements = [];
|
|
235
|
+
const mediumImpactReplacements = [];
|
|
236
|
+
const securityIssues = [];
|
|
237
|
+
const sizeMap = {};
|
|
238
|
+
for (const m of KNOWN_MAPPINGS) {
|
|
239
|
+
sizeMap[m.name] = m.size;
|
|
240
|
+
}
|
|
241
|
+
for (const mapping of KNOWN_MAPPINGS) {
|
|
242
|
+
const isDirect = directNames.has(mapping.name);
|
|
243
|
+
if (!isDirect) continue;
|
|
244
|
+
const isUsed = detectImportsInSrc(projectPath, mapping);
|
|
245
|
+
if (!isUsed && !config.verbose) continue;
|
|
246
|
+
const mappingSize = parseSize(sizeMap[mapping.name] ?? "0 KB");
|
|
247
|
+
const replacementSize = mapping.replacement.startsWith("native") ? 0 : 5;
|
|
248
|
+
const reductionStr = mappingSize > 1024 ? `${(mappingSize / 1024).toFixed(1)} MB \u2192 ${replacementSize} KB` : `${mappingSize.toFixed(0)} KB \u2192 ${replacementSize} KB`;
|
|
249
|
+
const suggestion = {
|
|
250
|
+
packageName: mapping.name,
|
|
251
|
+
reason: mapping.reason,
|
|
252
|
+
replacement: mapping.replacement,
|
|
253
|
+
estimatedSizeReduction: reductionStr,
|
|
254
|
+
confidence: mapping.confidence,
|
|
255
|
+
autoPrReady: mapping.autoPrReady
|
|
256
|
+
};
|
|
257
|
+
if (mapping.confidence === "high") {
|
|
258
|
+
highImpactReplacements.push(suggestion);
|
|
259
|
+
} else {
|
|
260
|
+
mediumImpactReplacements.push(suggestion);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
for (const [name, cves] of Object.entries(KNOWN_CVES)) {
|
|
264
|
+
if (directNames.has(name)) {
|
|
265
|
+
for (const cveItem of cves) {
|
|
266
|
+
securityIssues.push({
|
|
267
|
+
packageName: name,
|
|
268
|
+
cveId: cveItem.cve,
|
|
269
|
+
severity: cveItem.severity,
|
|
270
|
+
fix: cveItem.fix
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
let totalSizeKB = 0;
|
|
276
|
+
for (const depName of directNames) {
|
|
277
|
+
const sizeStr = sizeMap[depName];
|
|
278
|
+
if (sizeStr) {
|
|
279
|
+
totalSizeKB += parseSize(sizeStr);
|
|
280
|
+
} else {
|
|
281
|
+
totalSizeKB += 50;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
totalSizeKB += transitiveCount * 30;
|
|
285
|
+
const totalSizeStr = totalSizeKB > 1024 ? `${(totalSizeKB / 1024).toFixed(1)} MB` : `${totalSizeKB.toFixed(0)} KB`;
|
|
286
|
+
return {
|
|
287
|
+
projectName: pkg.name,
|
|
288
|
+
directDeps: directNames.size,
|
|
289
|
+
transitiveDeps: transitiveCount,
|
|
290
|
+
totalEstimatedSize: totalSizeStr,
|
|
291
|
+
highImpactReplacements,
|
|
292
|
+
mediumImpactReplacements,
|
|
293
|
+
securityIssues
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// src/dep-exray/reporter/index.ts
|
|
298
|
+
var _ = {
|
|
299
|
+
reset: "\x1B[0m",
|
|
300
|
+
bold: "\x1B[1m",
|
|
301
|
+
dim: "\x1B[2m",
|
|
302
|
+
red: "\x1B[31m",
|
|
303
|
+
green: "\x1B[32m",
|
|
304
|
+
yellow: "\x1B[33m",
|
|
305
|
+
blue: "\x1B[34m",
|
|
306
|
+
cyan: "\x1B[36m",
|
|
307
|
+
white: "\x1B[37m"
|
|
308
|
+
};
|
|
309
|
+
function style(text, codes) {
|
|
310
|
+
return codes.join("") + text + _.reset;
|
|
311
|
+
}
|
|
312
|
+
function severityColor(severity) {
|
|
313
|
+
switch (severity) {
|
|
314
|
+
case "critical":
|
|
315
|
+
return style(severity.toUpperCase(), [_.bold, _.red]);
|
|
316
|
+
case "high":
|
|
317
|
+
return style(severity.toUpperCase(), [_.red]);
|
|
318
|
+
case "medium":
|
|
319
|
+
return style(severity.toUpperCase(), [_.yellow]);
|
|
320
|
+
case "low":
|
|
321
|
+
return style(severity.toUpperCase(), [_.dim]);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
function confidenceIcon(confidence) {
|
|
325
|
+
switch (confidence) {
|
|
326
|
+
case "high":
|
|
327
|
+
return style("\u25CF", [_.green]);
|
|
328
|
+
case "medium":
|
|
329
|
+
return style("\u25CF", [_.yellow]);
|
|
330
|
+
case "low":
|
|
331
|
+
return style("\u25CF", [_.red]);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function generateReport(result, jsonOutput) {
|
|
335
|
+
if (jsonOutput) {
|
|
336
|
+
return JSON.stringify(result, null, 2);
|
|
337
|
+
}
|
|
338
|
+
const lines = [];
|
|
339
|
+
const t = (text, codes = [_.cyan]) => style(text, [_.bold, ...codes]);
|
|
340
|
+
lines.push(t(`\u250C${"\u2500".repeat(58)}\u2510`));
|
|
341
|
+
lines.push(t(`\u2502${" ".repeat(18)}dep-exray Report${" ".repeat(21)}\u2502`));
|
|
342
|
+
lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
|
|
343
|
+
lines.push(t(`\u2502 ${style("\u{1F4E6} PROJECT:", [_.white])} ${style(result.projectName, [_.bold])}${" ".repeat(Math.max(1, 47 - result.projectName.length))}\u2502`));
|
|
344
|
+
lines.push(t(`\u2502 ${style("\u{1F4CA} DEPENDENCIES:", [_.white])} ${style(String(result.directDeps), [_.bold])} direct + ${style(String(result.transitiveDeps), [_.bold])} transitive${" ".repeat(Math.max(1, 27 - String(result.transitiveDeps).length))}\u2502`));
|
|
345
|
+
lines.push(t(`\u2502 ${style("\u{1F4BE} TOTAL SIZE:", [_.white])} ${style(result.totalEstimatedSize, [_.bold])}${" ".repeat(Math.max(1, 42 - result.totalEstimatedSize.length))}\u2502`));
|
|
346
|
+
lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
|
|
347
|
+
if (result.highImpactReplacements.length > 0) {
|
|
348
|
+
lines.push(t(`\u2502 ${style("\u{1F7E2}", [_.green])} ${style("HIGH IMPACT REPLACEMENTS", [_.bold, _.green])}${" ".repeat(23)}\u2502`));
|
|
349
|
+
for (const item of result.highImpactReplacements) {
|
|
350
|
+
const autoPr = item.autoPrReady ? style("\u2713 Auto-PR ready", [_.green]) : style("Manual review needed", [_.dim]);
|
|
351
|
+
const confIcon = confidenceIcon(item.confidence);
|
|
352
|
+
lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
|
|
353
|
+
lines.push(t(`\u2502 ${style("\u2717", [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`));
|
|
354
|
+
lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${style(item.replacement, [_.cyan])}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`));
|
|
355
|
+
lines.push(t(`\u2502 ${style("\u2514\u2500", [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (result.mediumImpactReplacements.length > 0) {
|
|
359
|
+
lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
|
|
360
|
+
lines.push(t(`\u2502 ${style("\u{1F7E1}", [_.yellow])} ${style("MEDIUM IMPACT REPLACEMENTS", [_.bold, _.yellow])}${" ".repeat(20)}\u2502`));
|
|
361
|
+
for (const item of result.mediumImpactReplacements) {
|
|
362
|
+
const autoPr = item.autoPrReady ? style("\u2713 Auto-PR ready", [_.green]) : style("Manual review needed", [_.dim]);
|
|
363
|
+
const confIcon = confidenceIcon(item.confidence);
|
|
364
|
+
lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
|
|
365
|
+
lines.push(t(`\u2502 ${style("\u2717", [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${" ".repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}\u2502`));
|
|
366
|
+
lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${style(item.replacement, [_.cyan])}${" ".repeat(Math.max(1, 51 - item.replacement.length))}\u2502`));
|
|
367
|
+
lines.push(t(`\u2502 ${style("\u2514\u2500", [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${" ".repeat(Math.max(1, 35))}\u2502`));
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (result.securityIssues.length > 0) {
|
|
371
|
+
lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
|
|
372
|
+
lines.push(t(`\u2502 ${style("\u{1F534}", [_.red])} ${style("SECURITY ISSUES", [_.bold, _.red])}${" ".repeat(33)}\u2502`));
|
|
373
|
+
for (const issue of result.securityIssues) {
|
|
374
|
+
lines.push(t(`\u251C${"\u2500".repeat(58)}\u2524`));
|
|
375
|
+
lines.push(t(`\u2502 ${severityColor(issue.severity)} ${style(issue.cveId, [_.bold])} in ${issue.packageName}${" ".repeat(Math.max(1, 40 - issue.packageName.length))}\u2502`));
|
|
376
|
+
lines.push(t(`\u2502 ${style("\u2192", [_.dim])} ${issue.fix}${" ".repeat(Math.max(1, 52 - issue.fix.length))}\u2502`));
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
lines.push(t(`\u2514${"\u2500".repeat(58)}\u2518`));
|
|
380
|
+
return lines.join("\n");
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// src/dep-exray/analyzer/index.ts
|
|
384
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
385
|
+
import { readdirSync as readdirSync2, statSync } from "fs";
|
|
386
|
+
import { join as join2, extname } from "path";
|
|
387
|
+
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
388
|
+
function isSourceFile(file) {
|
|
389
|
+
return SOURCE_EXTENSIONS.has(extname(file));
|
|
390
|
+
}
|
|
391
|
+
function collectSourceFiles2(dir) {
|
|
392
|
+
const results = [];
|
|
393
|
+
try {
|
|
394
|
+
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
395
|
+
for (const entry of entries) {
|
|
396
|
+
const fullPath = join2(dir, entry.name);
|
|
397
|
+
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git" || entry.name === "coverage" || entry.name === ".tsup") {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
if (entry.isDirectory()) {
|
|
401
|
+
results.push(...collectSourceFiles2(fullPath));
|
|
402
|
+
} else if (entry.isFile() && isSourceFile(entry.name)) {
|
|
403
|
+
results.push(fullPath);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
} catch {
|
|
407
|
+
}
|
|
408
|
+
return results;
|
|
409
|
+
}
|
|
410
|
+
function escapeRegex(str) {
|
|
411
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
412
|
+
}
|
|
413
|
+
async function analyzeUsage(projectPath, packageName) {
|
|
414
|
+
const importLocations = [];
|
|
415
|
+
const escaped = escapeRegex(packageName);
|
|
416
|
+
const importRegex = new RegExp(
|
|
417
|
+
`(?:from\\s+['"]${escaped}(?:/['"]|['"])|require\\(\\s*['"]${escaped}(?:/|['"]))`,
|
|
418
|
+
"g"
|
|
419
|
+
);
|
|
420
|
+
const srcDir = join2(projectPath, "src");
|
|
421
|
+
let files;
|
|
422
|
+
try {
|
|
423
|
+
if (statSync(srcDir).isDirectory()) {
|
|
424
|
+
files = collectSourceFiles2(srcDir);
|
|
425
|
+
} else {
|
|
426
|
+
files = collectSourceFiles2(projectPath);
|
|
427
|
+
}
|
|
428
|
+
} catch {
|
|
429
|
+
files = collectSourceFiles2(projectPath);
|
|
430
|
+
}
|
|
431
|
+
for (const file of files) {
|
|
432
|
+
try {
|
|
433
|
+
const content = readFileSync2(file, "utf-8");
|
|
434
|
+
importRegex.lastIndex = 0;
|
|
435
|
+
if (importRegex.test(content)) {
|
|
436
|
+
importLocations.push(file);
|
|
437
|
+
}
|
|
438
|
+
} catch {
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return {
|
|
442
|
+
isUsed: importLocations.length > 0,
|
|
443
|
+
importCount: importLocations.length,
|
|
444
|
+
importLocations
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
export {
|
|
448
|
+
KNOWN_CVES,
|
|
449
|
+
KNOWN_MAPPINGS,
|
|
450
|
+
analyzeUsage,
|
|
451
|
+
generateReport,
|
|
452
|
+
scanProject
|
|
453
|
+
};
|
|
454
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/dep-exray/scanner/index.ts","../../src/dep-exray/known-mappings.ts","../../src/dep-exray/reporter/index.ts","../../src/dep-exray/analyzer/index.ts"],"sourcesContent":["import { readFileSync, readdirSync, existsSync } from 'node:fs'\r\nimport { join, basename } from 'node:path'\r\nimport type { ScanResult, ReplacementSuggestion, SecurityIssue, ScannerConfig } from '../types.js'\r\nimport { KNOWN_MAPPINGS, KNOWN_CVES, type PackageMapping } from '../known-mappings.js'\r\n\r\ninterface LockfilePackages {\r\n [key: string]: { version?: string; dependencies?: Record<string, string> } | undefined\r\n}\r\n\r\ninterface LockfileData {\r\n packages: LockfilePackages\r\n}\r\n\r\nfunction parsePackageJson(path: string): { name: string; dependencies: Record<string, string>; devDependencies: Record<string, string> } {\r\n const raw = readFileSync(path, 'utf-8')\r\n const json = JSON.parse(raw)\r\n return {\r\n name: json.name ?? basename(join(path, '..')),\r\n dependencies: (json.dependencies as Record<string, string>) ?? {},\r\n devDependencies: (json.devDependencies as Record<string, string>) ?? {},\r\n }\r\n}\r\n\r\nfunction parseLockfile(projectPath: string): LockfileData | null {\r\n const lockPath = join(projectPath, 'package-lock.json')\r\n if (!existsSync(lockPath)) return null\r\n try {\r\n const raw = readFileSync(lockPath, 'utf-8')\r\n const json = JSON.parse(raw)\r\n const packages: LockfilePackages = {}\r\n\r\n if (json.packages) {\r\n for (const [key, val] of Object.entries(json.packages as Record<string, { version?: string }>)) {\r\n if (key) {\r\n packages[key] = val\r\n }\r\n }\r\n }\r\n\r\n if (json.dependencies && Object.keys(packages).length === 0) {\r\n for (const [key, val] of Object.entries(json.dependencies as Record<string, { version?: string; requires?: Record<string, string> }>)) {\r\n packages[key] = { version: val.version, dependencies: val.requires }\r\n }\r\n }\r\n\r\n return { packages }\r\n } catch {\r\n return null\r\n }\r\n}\r\n\r\nfunction detectImportInFile(filePath: string, regex: RegExp): boolean {\r\n try {\r\n const content = readFileSync(filePath, 'utf-8')\r\n return regex.test(content)\r\n } catch {\r\n return false\r\n }\r\n}\r\n\r\nfunction detectImportsInSrc(projectPath: string, mapping: PackageMapping): boolean {\r\n const regex = new RegExp(mapping.detectionPattern)\r\n const srcDir = join(projectPath, 'src')\r\n if (!existsSync(srcDir)) return false\r\n\r\n try {\r\n const files = collectSourceFiles(srcDir)\r\n for (const file of files) {\r\n if (detectImportInFile(file, regex)) return true\r\n }\r\n } catch {\r\n return false\r\n }\r\n return false\r\n}\r\n\r\nfunction collectSourceFiles(dir: string): string[] {\r\n const results: string[] = []\r\n try {\r\n const entries = readdirSync(dir, { withFileTypes: true })\r\n for (const entry of entries) {\r\n if (entry.name === 'node_modules' || entry.name === 'dist' || entry.name === '.git' || entry.name === 'coverage' || entry.name === '.tsup') {\r\n continue\r\n }\r\n const full = join(dir, entry.name)\r\n if (entry.isDirectory()) {\r\n results.push(...collectSourceFiles(full))\r\n } else if (entry.isFile()) {\r\n const ext = entry.name.split('.').pop()\r\n if (ext === 'ts' || ext === 'tsx' || ext === 'js' || ext === 'jsx' || ext === 'mjs' || ext === 'cjs') {\r\n results.push(full)\r\n }\r\n }\r\n }\r\n } catch {\r\n // skip inaccessible dirs\r\n }\r\n return results\r\n}\r\n\r\nfunction estimateTransitiveCount(lockfile: LockfileData | null, directNames: Set<string>): number {\r\n if (!lockfile) return 0\r\n let count = 0\r\n for (const key of Object.keys(lockfile.packages)) {\r\n if (!key || key === '') continue\r\n const name = key.startsWith('node_modules/') ? key.slice('node_modules/'.length) : key\r\n const rootName = name.startsWith('@') ? `${name.split('/')[0]}/${name.split('/')[1]}` : name.split('/')[0]\r\n if (rootName && !directNames.has(rootName)) {\r\n count++\r\n }\r\n }\r\n return count\r\n}\r\n\r\nfunction parseSize(value: string): number {\r\n const cleaned = value.replace(/\\(.*?\\)/g, '').trim()\r\n const match = cleaned.match(/^([\\d.]+)\\s*(KB|MB)/i)\r\n if (!match) return 0\r\n const num = Number.parseFloat(match[1]!)\r\n if (!match[2]) return 0\r\n if (match[2].toUpperCase() === 'MB') return num * 1024\r\n return num\r\n}\r\n\r\nexport async function scanProject(config: ScannerConfig): Promise<ScanResult> {\r\n const projectPath = config.path ?? '.'\r\n const pkgPath = join(projectPath, 'package.json')\r\n\r\n if (!existsSync(pkgPath)) {\r\n throw new Error(`No package.json found at ${projectPath}. Run dep-exray in a JavaScript/TypeScript project directory.`)\r\n }\r\n\r\n const pkg = parsePackageJson(pkgPath)\r\n const lockfile = parseLockfile(projectPath)\r\n\r\n const allDeps: Record<string, string> = { ...pkg.dependencies, ...pkg.devDependencies }\r\n const directNames = new Set(Object.keys(allDeps))\r\n\r\n const transitiveCount = estimateTransitiveCount(lockfile, directNames)\r\n\r\n const highImpactReplacements: ReplacementSuggestion[] = []\r\n const mediumImpactReplacements: ReplacementSuggestion[] = []\r\n const securityIssues: SecurityIssue[] = []\r\n\r\n const sizeMap: Record<string, string> = {}\r\n for (const m of KNOWN_MAPPINGS) {\r\n sizeMap[m.name] = m.size\r\n }\r\n\r\n for (const mapping of KNOWN_MAPPINGS) {\r\n const isDirect = directNames.has(mapping.name)\r\n if (!isDirect) continue\r\n\r\n const isUsed = detectImportsInSrc(projectPath, mapping)\r\n if (!isUsed && !config.verbose) continue\r\n\r\n const mappingSize = parseSize(sizeMap[mapping.name] ?? '0 KB')\r\n const replacementSize = mapping.replacement.startsWith('native') ? 0 : 5\r\n const reductionStr = mappingSize > 1024\r\n ? `${(mappingSize / 1024).toFixed(1)} MB → ${replacementSize} KB`\r\n : `${mappingSize.toFixed(0)} KB → ${replacementSize} KB`\r\n\r\n const suggestion: ReplacementSuggestion = {\r\n packageName: mapping.name,\r\n reason: mapping.reason,\r\n replacement: mapping.replacement,\r\n estimatedSizeReduction: reductionStr,\r\n confidence: mapping.confidence,\r\n autoPrReady: mapping.autoPrReady,\r\n }\r\n\r\n if (mapping.confidence === 'high') {\r\n highImpactReplacements.push(suggestion)\r\n } else {\r\n mediumImpactReplacements.push(suggestion)\r\n }\r\n }\r\n\r\n for (const [name, cves] of Object.entries(KNOWN_CVES)) {\r\n if (directNames.has(name)) {\r\n for (const cveItem of cves) {\r\n securityIssues.push({\r\n packageName: name,\r\n cveId: cveItem.cve,\r\n severity: cveItem.severity as SecurityIssue['severity'],\r\n fix: cveItem.fix,\r\n })\r\n }\r\n }\r\n }\r\n\r\n let totalSizeKB = 0\r\n for (const depName of directNames) {\r\n const sizeStr = sizeMap[depName]\r\n if (sizeStr) {\r\n totalSizeKB += parseSize(sizeStr)\r\n } else {\r\n totalSizeKB += 50\r\n }\r\n }\r\n totalSizeKB += transitiveCount * 30\r\n\r\n const totalSizeStr = totalSizeKB > 1024\r\n ? `${(totalSizeKB / 1024).toFixed(1)} MB`\r\n : `${totalSizeKB.toFixed(0)} KB`\r\n\r\n return {\r\n projectName: pkg.name,\r\n directDeps: directNames.size,\r\n transitiveDeps: transitiveCount,\r\n totalEstimatedSize: totalSizeStr,\r\n highImpactReplacements,\r\n mediumImpactReplacements,\r\n securityIssues,\r\n }\r\n}\r\n","\r\n\r\nexport interface PackageMapping {\r\n name: string\r\n size: string\r\n replacement: string\r\n confidence: 'high' | 'medium' | 'low'\r\n autoPrReady: boolean\r\n reason: string\r\n detectionPattern: string\r\n}\r\n\r\nexport const KNOWN_MAPPINGS: PackageMapping[] = [\r\n {\r\n name: 'lodash',\r\n size: '4.2 MB',\r\n replacement: 'jscore-core',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'Most lodash functions have direct replacements in jscore-core with 99% API compatibility',\r\n detectionPattern: 'from [\\'\"]lodash[\\'\"]|require\\\\([\\'\"]lodash[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'moment',\r\n size: '2.5 MB',\r\n replacement: 'jscore-core/date',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'date utilities in jscore-core cover 95% of common moment use cases',\r\n detectionPattern: 'from [\\'\"]moment[\\'\"]|require\\\\([\\'\"]moment[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'date-fns',\r\n size: '1.2 MB (tree-shaked ~50KB)',\r\n replacement: 'jscore-core/date',\r\n confidence: 'medium',\r\n autoPrReady: false,\r\n reason: 'Partially overlapping — jscore-core covers basic date ops but not all locale support',\r\n detectionPattern: 'from [\\'\"]date-fns[\\'\"]|require\\\\([\\'\"]date-fns[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'axios',\r\n size: '1.6 MB',\r\n replacement: 'native fetch + jscore-core/async/retry',\r\n confidence: 'medium',\r\n autoPrReady: false,\r\n reason: 'Native fetch covers most use cases; needs manual review for interceptors',\r\n detectionPattern: 'from [\\'\"]axios[\\'\"]|require\\\\([\\'\"]axios[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'uuid',\r\n size: '30 KB',\r\n replacement: 'crypto.randomUUID() (native)',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'crypto.randomUUID() is available in all modern Node.js and browsers',\r\n detectionPattern: 'from [\\'\"]uuid[\\'\"]|require\\\\([\\'\"]uuid[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'deepmerge',\r\n size: '15 KB',\r\n replacement: 'jscore-core',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'jscore-core provides deepMerge out of the box',\r\n detectionPattern: 'from [\\'\"]deepmerge[\\'\"]|require\\\\([\\'\"]deepmerge[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'lodash.merge',\r\n size: '25 KB',\r\n replacement: 'jscore-core',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'jscore-core provides deepMerge out of the box',\r\n detectionPattern: 'from [\\'\"]lodash\\\\.(merge|clone|pick|omit|get|set)[\\'\"]',\r\n },\r\n {\r\n name: 'chalk',\r\n size: '45 KB',\r\n replacement: 'picocolors',\r\n confidence: 'medium',\r\n autoPrReady: false,\r\n reason: \"picocolors is 3KB vs chalk's 45KB with same API\",\r\n detectionPattern: 'from [\\'\"]chalk[\\'\"]|require\\\\([\\'\"]chalk[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'nanoid',\r\n size: '8 KB',\r\n replacement: 'jscore-core/string (nanoid)',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'jscore-core provides nanoid with same API',\r\n detectionPattern: 'from [\\'\"]nanoid[\\'\"]|require\\\\([\\'\"]nanoid[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'dayjs',\r\n size: '50 KB',\r\n replacement: 'jscore-core/date',\r\n confidence: 'medium',\r\n autoPrReady: false,\r\n reason: 'Partially overlapping — covers basics but not all plugins',\r\n detectionPattern: 'from [\\'\"]dayjs[\\'\"]|require\\\\([\\'\"]dayjs[\\'\"]\\\\)',\r\n },\r\n {\r\n name: 'clsx',\r\n size: '5 KB',\r\n replacement: 'native template literals',\r\n confidence: 'high',\r\n autoPrReady: true,\r\n reason: 'Can be replaced with simple template literal conditional pattern',\r\n detectionPattern: 'from [\\'\"]clsx[\\'\"]|require\\\\([\\'\"]clsx[\\'\"]\\\\)',\r\n },\r\n]\r\n\r\nexport const KNOWN_CVES: Record<string, { cve: string; severity: string; fix: string }[]> = {\r\n 'ansi-regex': [\r\n { cve: 'CVE-2021-3807', severity: 'high', fix: 'Update to ansi-regex@6.0.1 or later' },\r\n ],\r\n 'semver': [\r\n { cve: 'CVE-2022-25883', severity: 'medium', fix: 'Update to semver@7.5.2 or later' },\r\n ],\r\n 'json5': [\r\n { cve: 'CVE-2022-46175', severity: 'high', fix: 'Update to json5@2.2.3 or later' },\r\n ],\r\n 'lodash': [\r\n { cve: 'CVE-2020-28502', severity: 'high', fix: 'Update to lodash@4.17.21 or later' },\r\n { cve: 'CVE-2020-8203', severity: 'medium', fix: 'Update to lodash@4.17.21 or later' },\r\n ],\r\n}\r\n","import type { ScanResult, ReplacementSuggestion, SecurityIssue } from '../types.js'\n\n// ANSI color codes — zero dependencies\nconst _ = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n cyan: '\\x1b[36m',\n white: '\\x1b[37m',\n}\n\nfunction style(text: string, codes: string[]): string {\n return codes.join('') + text + _.reset\n}\n\nfunction severityColor(severity: SecurityIssue['severity']): string {\n switch (severity) {\n case 'critical': return style(severity.toUpperCase(), [_.bold, _.red])\n case 'high': return style(severity.toUpperCase(), [_.red])\n case 'medium': return style(severity.toUpperCase(), [_.yellow])\n case 'low': return style(severity.toUpperCase(), [_.dim])\n }\n}\n\nfunction confidenceIcon(confidence: ReplacementSuggestion['confidence']): string {\n switch (confidence) {\n case 'high': return style('●', [_.green])\n case 'medium': return style('●', [_.yellow])\n case 'low': return style('●', [_.red])\n }\n}\n\nexport function generateReport(result: ScanResult, jsonOutput?: boolean): string {\n if (jsonOutput) {\n return JSON.stringify(result, null, 2)\n }\n\n const lines: string[] = []\n\n const t = (text: string, codes: string[] = [_.cyan]) => style(text, [_.bold, ...codes])\n\n lines.push(t(`┌${'─'.repeat(58)}┐`))\n lines.push(t(`│${' '.repeat(18)}dep-exray Report${' '.repeat(21)}│`))\n lines.push(t(`├${'─'.repeat(58)}┤`))\n lines.push(t(`│ ${style('📦 PROJECT:', [_.white])} ${style(result.projectName, [_.bold])}${' '.repeat(Math.max(1, 47 - result.projectName.length))}│`))\n lines.push(t(`│ ${style('📊 DEPENDENCIES:', [_.white])} ${style(String(result.directDeps), [_.bold])} direct + ${style(String(result.transitiveDeps), [_.bold])} transitive${' '.repeat(Math.max(1, 27 - String(result.transitiveDeps).length))}│`))\n lines.push(t(`│ ${style('💾 TOTAL SIZE:', [_.white])} ${style(result.totalEstimatedSize, [_.bold])}${' '.repeat(Math.max(1, 42 - result.totalEstimatedSize.length))}│`))\n lines.push(t(`├${'─'.repeat(58)}┤`))\n\n if (result.highImpactReplacements.length > 0) {\n lines.push(t(`│ ${style('🟢', [_.green])} ${style('HIGH IMPACT REPLACEMENTS', [_.bold, _.green])}${' '.repeat(23)}│`))\n for (const item of result.highImpactReplacements) {\n const autoPr = item.autoPrReady ? style('✓ Auto-PR ready', [_.green]) : style('Manual review needed', [_.dim])\n const confIcon = confidenceIcon(item.confidence)\n lines.push(t(`├${'─'.repeat(58)}┤`))\n lines.push(t(`│ ${style('✗', [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${' '.repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}│`))\n lines.push(t(`│ ${style('→', [_.dim])} ${style(item.replacement, [_.cyan])}${' '.repeat(Math.max(1, 51 - item.replacement.length))}│`))\n lines.push(t(`│ ${style('└─', [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${' '.repeat(Math.max(1, 35))}│`))\n }\n }\n\n if (result.mediumImpactReplacements.length > 0) {\n lines.push(t(`├${'─'.repeat(58)}┤`))\n lines.push(t(`│ ${style('🟡', [_.yellow])} ${style('MEDIUM IMPACT REPLACEMENTS', [_.bold, _.yellow])}${' '.repeat(20)}│`))\n for (const item of result.mediumImpactReplacements) {\n const autoPr = item.autoPrReady ? style('✓ Auto-PR ready', [_.green]) : style('Manual review needed', [_.dim])\n const confIcon = confidenceIcon(item.confidence)\n lines.push(t(`├${'─'.repeat(58)}┤`))\n lines.push(t(`│ ${style('✗', [_.red])} ${style(item.packageName, [_.bold])} (${item.estimatedSizeReduction})${' '.repeat(Math.max(1, 38 - item.estimatedSizeReduction.length))}│`))\n lines.push(t(`│ ${style('→', [_.dim])} ${style(item.replacement, [_.cyan])}${' '.repeat(Math.max(1, 51 - item.replacement.length))}│`))\n lines.push(t(`│ ${style('└─', [_.dim])} ${autoPr} ${confIcon} ${item.confidence}${' '.repeat(Math.max(1, 35))}│`))\n }\n }\n\n if (result.securityIssues.length > 0) {\n lines.push(t(`├${'─'.repeat(58)}┤`))\n lines.push(t(`│ ${style('🔴', [_.red])} ${style('SECURITY ISSUES', [_.bold, _.red])}${' '.repeat(33)}│`))\n for (const issue of result.securityIssues) {\n lines.push(t(`├${'─'.repeat(58)}┤`))\n lines.push(t(`│ ${severityColor(issue.severity)} ${style(issue.cveId, [_.bold])} in ${issue.packageName}${' '.repeat(Math.max(1, 40 - issue.packageName.length))}│`))\n lines.push(t(`│ ${style('→', [_.dim])} ${issue.fix}${' '.repeat(Math.max(1, 52 - issue.fix.length))}│`))\n }\n }\n\n lines.push(t(`└${'─'.repeat(58)}┘`))\n\n return lines.join('\\n')\n}\n","import { readFileSync } from 'node:fs'\r\nimport { readdirSync, statSync } from 'node:fs'\r\nimport { join, extname } from 'node:path'\r\n\r\nconst SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'])\r\n\r\nfunction isSourceFile(file: string): boolean {\r\n return SOURCE_EXTENSIONS.has(extname(file))\r\n}\r\n\r\nfunction collectSourceFiles(dir: string): string[] {\r\n const results: string[] = []\r\n try {\r\n const entries = readdirSync(dir, { withFileTypes: true })\r\n for (const entry of entries) {\r\n const fullPath = join(dir, entry.name)\r\n if (entry.name === 'node_modules' || entry.name === 'dist' || entry.name === '.git' || entry.name === 'coverage' || entry.name === '.tsup') {\r\n continue\r\n }\r\n if (entry.isDirectory()) {\r\n results.push(...collectSourceFiles(fullPath))\r\n } else if (entry.isFile() && isSourceFile(entry.name)) {\r\n results.push(fullPath)\r\n }\r\n }\r\n } catch {\r\n // skip directories we can't read\r\n }\r\n return results\r\n}\r\n\r\nfunction escapeRegex(str: string): string {\r\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\r\n}\r\n\r\nexport async function analyzeUsage(\r\n projectPath: string,\r\n packageName: string,\r\n): Promise<{\r\n isUsed: boolean\r\n importCount: number\r\n importLocations: string[]\r\n}> {\r\n const importLocations: string[] = []\r\n const escaped = escapeRegex(packageName)\r\n const importRegex = new RegExp(\r\n `(?:from\\\\s+['\"]${escaped}(?:/['\"]|['\"])|require\\\\(\\\\s*['\"]${escaped}(?:/|['\"]))`,\r\n 'g',\r\n )\r\n\r\n const srcDir = join(projectPath, 'src')\r\n let files: string[]\r\n try {\r\n if (statSync(srcDir).isDirectory()) {\r\n files = collectSourceFiles(srcDir)\r\n } else {\r\n files = collectSourceFiles(projectPath)\r\n }\r\n } catch {\r\n files = collectSourceFiles(projectPath)\r\n }\r\n\r\n for (const file of files) {\r\n try {\r\n const content = readFileSync(file, 'utf-8')\r\n importRegex.lastIndex = 0\r\n if (importRegex.test(content)) {\r\n importLocations.push(file)\r\n }\r\n } catch {\r\n // skip unreadable files\r\n }\r\n }\r\n\r\n return {\r\n isUsed: importLocations.length > 0,\r\n importCount: importLocations.length,\r\n importLocations,\r\n }\r\n}\r\n"],"mappings":"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","names":["readFileSync","readdirSync","join","collectSourceFiles"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface PackageMapping {
|
|
2
|
+
name: string;
|
|
3
|
+
size: string;
|
|
4
|
+
replacement: string;
|
|
5
|
+
confidence: 'high' | 'medium' | 'low';
|
|
6
|
+
autoPrReady: boolean;
|
|
7
|
+
reason: string;
|
|
8
|
+
detectionPattern: string;
|
|
9
|
+
}
|
|
10
|
+
declare const KNOWN_MAPPINGS: PackageMapping[];
|
|
11
|
+
declare const KNOWN_CVES: Record<string, {
|
|
12
|
+
cve: string;
|
|
13
|
+
severity: string;
|
|
14
|
+
fix: string;
|
|
15
|
+
}[]>;
|
|
16
|
+
|
|
17
|
+
export { KNOWN_CVES, KNOWN_MAPPINGS, type PackageMapping };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// src/dep-exray/known-mappings.ts
|
|
2
|
+
var KNOWN_MAPPINGS = [
|
|
3
|
+
{
|
|
4
|
+
name: "lodash",
|
|
5
|
+
size: "4.2 MB",
|
|
6
|
+
replacement: "jscore-core",
|
|
7
|
+
confidence: "high",
|
|
8
|
+
autoPrReady: true,
|
|
9
|
+
reason: "Most lodash functions have direct replacements in jscore-core with 99% API compatibility",
|
|
10
|
+
detectionPattern: `from ['"]lodash['"]|require\\(['"]lodash['"]\\)`
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: "moment",
|
|
14
|
+
size: "2.5 MB",
|
|
15
|
+
replacement: "jscore-core/date",
|
|
16
|
+
confidence: "high",
|
|
17
|
+
autoPrReady: true,
|
|
18
|
+
reason: "date utilities in jscore-core cover 95% of common moment use cases",
|
|
19
|
+
detectionPattern: `from ['"]moment['"]|require\\(['"]moment['"]\\)`
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "date-fns",
|
|
23
|
+
size: "1.2 MB (tree-shaked ~50KB)",
|
|
24
|
+
replacement: "jscore-core/date",
|
|
25
|
+
confidence: "medium",
|
|
26
|
+
autoPrReady: false,
|
|
27
|
+
reason: "Partially overlapping \u2014 jscore-core covers basic date ops but not all locale support",
|
|
28
|
+
detectionPattern: `from ['"]date-fns['"]|require\\(['"]date-fns['"]\\)`
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "axios",
|
|
32
|
+
size: "1.6 MB",
|
|
33
|
+
replacement: "native fetch + jscore-core/async/retry",
|
|
34
|
+
confidence: "medium",
|
|
35
|
+
autoPrReady: false,
|
|
36
|
+
reason: "Native fetch covers most use cases; needs manual review for interceptors",
|
|
37
|
+
detectionPattern: `from ['"]axios['"]|require\\(['"]axios['"]\\)`
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "uuid",
|
|
41
|
+
size: "30 KB",
|
|
42
|
+
replacement: "crypto.randomUUID() (native)",
|
|
43
|
+
confidence: "high",
|
|
44
|
+
autoPrReady: true,
|
|
45
|
+
reason: "crypto.randomUUID() is available in all modern Node.js and browsers",
|
|
46
|
+
detectionPattern: `from ['"]uuid['"]|require\\(['"]uuid['"]\\)`
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "deepmerge",
|
|
50
|
+
size: "15 KB",
|
|
51
|
+
replacement: "jscore-core",
|
|
52
|
+
confidence: "high",
|
|
53
|
+
autoPrReady: true,
|
|
54
|
+
reason: "jscore-core provides deepMerge out of the box",
|
|
55
|
+
detectionPattern: `from ['"]deepmerge['"]|require\\(['"]deepmerge['"]\\)`
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "lodash.merge",
|
|
59
|
+
size: "25 KB",
|
|
60
|
+
replacement: "jscore-core",
|
|
61
|
+
confidence: "high",
|
|
62
|
+
autoPrReady: true,
|
|
63
|
+
reason: "jscore-core provides deepMerge out of the box",
|
|
64
|
+
detectionPattern: `from ['"]lodash\\.(merge|clone|pick|omit|get|set)['"]`
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "chalk",
|
|
68
|
+
size: "45 KB",
|
|
69
|
+
replacement: "picocolors",
|
|
70
|
+
confidence: "medium",
|
|
71
|
+
autoPrReady: false,
|
|
72
|
+
reason: "picocolors is 3KB vs chalk's 45KB with same API",
|
|
73
|
+
detectionPattern: `from ['"]chalk['"]|require\\(['"]chalk['"]\\)`
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: "nanoid",
|
|
77
|
+
size: "8 KB",
|
|
78
|
+
replacement: "jscore-core/string (nanoid)",
|
|
79
|
+
confidence: "high",
|
|
80
|
+
autoPrReady: true,
|
|
81
|
+
reason: "jscore-core provides nanoid with same API",
|
|
82
|
+
detectionPattern: `from ['"]nanoid['"]|require\\(['"]nanoid['"]\\)`
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: "dayjs",
|
|
86
|
+
size: "50 KB",
|
|
87
|
+
replacement: "jscore-core/date",
|
|
88
|
+
confidence: "medium",
|
|
89
|
+
autoPrReady: false,
|
|
90
|
+
reason: "Partially overlapping \u2014 covers basics but not all plugins",
|
|
91
|
+
detectionPattern: `from ['"]dayjs['"]|require\\(['"]dayjs['"]\\)`
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: "clsx",
|
|
95
|
+
size: "5 KB",
|
|
96
|
+
replacement: "native template literals",
|
|
97
|
+
confidence: "high",
|
|
98
|
+
autoPrReady: true,
|
|
99
|
+
reason: "Can be replaced with simple template literal conditional pattern",
|
|
100
|
+
detectionPattern: `from ['"]clsx['"]|require\\(['"]clsx['"]\\)`
|
|
101
|
+
}
|
|
102
|
+
];
|
|
103
|
+
var KNOWN_CVES = {
|
|
104
|
+
"ansi-regex": [
|
|
105
|
+
{ cve: "CVE-2021-3807", severity: "high", fix: "Update to ansi-regex@6.0.1 or later" }
|
|
106
|
+
],
|
|
107
|
+
"semver": [
|
|
108
|
+
{ cve: "CVE-2022-25883", severity: "medium", fix: "Update to semver@7.5.2 or later" }
|
|
109
|
+
],
|
|
110
|
+
"json5": [
|
|
111
|
+
{ cve: "CVE-2022-46175", severity: "high", fix: "Update to json5@2.2.3 or later" }
|
|
112
|
+
],
|
|
113
|
+
"lodash": [
|
|
114
|
+
{ cve: "CVE-2020-28502", severity: "high", fix: "Update to lodash@4.17.21 or later" },
|
|
115
|
+
{ cve: "CVE-2020-8203", severity: "medium", fix: "Update to lodash@4.17.21 or later" }
|
|
116
|
+
]
|
|
117
|
+
};
|
|
118
|
+
export {
|
|
119
|
+
KNOWN_CVES,
|
|
120
|
+
KNOWN_MAPPINGS
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=known-mappings.js.map
|