dotenv-diff 2.4.7 → 2.4.9
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 +19 -0
- package/dist/src/cli/run.js +2 -2
- package/dist/src/cli/run.js.map +1 -1
- package/dist/src/commands/compare.js +1 -1
- package/dist/src/commands/compare.js.map +1 -1
- package/dist/src/commands/ensureFilesOrPrompt.d.ts +22 -0
- package/dist/src/commands/ensureFilesOrPrompt.d.ts.map +1 -0
- package/dist/src/commands/ensureFilesOrPrompt.js +76 -0
- package/dist/src/commands/ensureFilesOrPrompt.js.map +1 -0
- package/dist/src/commands/scanUsage.js +6 -6
- package/dist/src/commands/scanUsage.js.map +1 -1
- package/dist/src/config/types.d.ts +3 -2
- package/dist/src/config/types.d.ts.map +1 -1
- package/dist/src/config/types.js +2 -2
- package/dist/src/config/types.js.map +1 -1
- package/dist/src/core/computeHealthScore.d.ts.map +1 -1
- package/dist/src/core/computeHealthScore.js +3 -0
- package/dist/src/core/computeHealthScore.js.map +1 -1
- package/dist/src/core/detectInconsistentNaming.js +0 -7
- package/dist/src/core/detectInconsistentNaming.js.map +1 -1
- package/dist/src/core/duplicates.d.ts +5 -4
- package/dist/src/core/duplicates.d.ts.map +1 -0
- package/dist/src/core/duplicates.js +5 -2
- package/dist/src/core/duplicates.js.map +1 -0
- package/dist/src/core/envDiscovery.d.ts +19 -0
- package/dist/src/core/envDiscovery.d.ts.map +1 -0
- package/dist/src/core/envDiscovery.js +81 -0
- package/dist/src/core/envDiscovery.js.map +1 -0
- package/dist/src/core/exampleSecretDetector.d.ts.map +1 -1
- package/dist/src/core/exampleSecretDetector.js +2 -2
- package/dist/src/core/exampleSecretDetector.js.map +1 -1
- package/dist/src/core/frameworks/frameworkDetector.d.ts +14 -0
- package/dist/src/core/frameworks/frameworkDetector.d.ts.map +1 -0
- package/dist/src/core/frameworks/frameworkDetector.js +40 -0
- package/dist/src/core/frameworks/frameworkDetector.js.map +1 -0
- package/dist/src/core/frameworks/frameworkValidator.d.ts +10 -0
- package/dist/src/core/frameworks/frameworkValidator.d.ts.map +1 -0
- package/dist/src/core/frameworks/frameworkValidator.js +21 -0
- package/dist/src/core/frameworks/frameworkValidator.js.map +1 -0
- package/dist/src/core/frameworks/nextJsRules.d.ts.map +1 -1
- package/dist/src/core/frameworks/nextJsRules.js +4 -28
- package/dist/src/core/frameworks/nextJsRules.js.map +1 -1
- package/dist/src/core/frameworks/sveltekitRules.d.ts.map +1 -1
- package/dist/src/core/frameworks/sveltekitRules.js +37 -30
- package/dist/src/core/frameworks/sveltekitRules.js.map +1 -1
- package/dist/src/core/parseEnv.d.ts.map +1 -1
- package/dist/src/core/parseEnv.js +19 -1
- package/dist/src/core/parseEnv.js.map +1 -1
- package/dist/src/core/patterns.d.ts.map +1 -1
- package/dist/src/core/patterns.js +24 -1
- package/dist/src/core/patterns.js.map +1 -1
- package/dist/src/core/processComparisonFile.js +1 -1
- package/dist/src/core/processComparisonFile.js.map +1 -1
- package/dist/src/core/scan/scanJsonOutput.d.ts +85 -0
- package/dist/src/core/scan/scanJsonOutput.d.ts.map +1 -0
- package/dist/src/core/scan/scanJsonOutput.js +97 -0
- package/dist/src/core/scan/scanJsonOutput.js.map +1 -0
- package/dist/src/core/scan/secretDetectors.d.ts +28 -0
- package/dist/src/core/scan/secretDetectors.d.ts.map +1 -0
- package/dist/src/core/scan/secretDetectors.js +272 -0
- package/dist/src/core/scan/secretDetectors.js.map +1 -0
- package/dist/src/core/scanFile.d.ts.map +1 -1
- package/dist/src/core/scanFile.js +11 -1
- package/dist/src/core/scanFile.js.map +1 -1
- package/dist/src/core/security/entropy.d.ts +8 -0
- package/dist/src/core/security/entropy.d.ts.map +1 -0
- package/dist/src/core/security/entropy.js +23 -0
- package/dist/src/core/security/entropy.js.map +1 -0
- package/dist/src/core/security/exampleSecretDetector.d.ts +13 -0
- package/dist/src/core/security/exampleSecretDetector.d.ts.map +1 -0
- package/dist/src/core/security/exampleSecretDetector.js +61 -0
- package/dist/src/core/security/exampleSecretDetector.js.map +1 -0
- package/dist/src/core/security/secretDetectors.d.ts +28 -0
- package/dist/src/core/security/secretDetectors.d.ts.map +1 -0
- package/dist/src/core/security/secretDetectors.js +292 -0
- package/dist/src/core/security/secretDetectors.js.map +1 -0
- package/dist/src/index.js +0 -7
- package/dist/src/index.js.map +1 -1
- package/dist/src/services/printScanResult.d.ts +17 -0
- package/dist/src/services/printScanResult.d.ts.map +1 -0
- package/dist/src/services/printScanResult.js +127 -0
- package/dist/src/services/printScanResult.js.map +1 -0
- package/dist/src/services/scanCodebase.d.ts +8 -0
- package/dist/src/services/scanCodebase.d.ts.map +1 -0
- package/dist/src/services/scanCodebase.js +110 -0
- package/dist/src/services/scanCodebase.js.map +1 -0
- package/dist/src/ui/scan/printConsolelogWarning.d.ts.map +1 -1
- package/dist/src/ui/scan/printConsolelogWarning.js +5 -4
- package/dist/src/ui/scan/printConsolelogWarning.js.map +1 -1
- package/dist/src/ui/scan/printExampleWarnings.d.ts +1 -1
- package/dist/src/ui/scan/printExampleWarnings.d.ts.map +1 -1
- package/dist/src/ui/scan/printFrameworkWarnings.d.ts.map +1 -1
- package/dist/src/ui/scan/printFrameworkWarnings.js +4 -2
- package/dist/src/ui/scan/printFrameworkWarnings.js.map +1 -1
- package/dist/src/ui/scan/printSecrets.d.ts +1 -1
- package/dist/src/ui/scan/printSecrets.d.ts.map +1 -1
- package/package.json +8 -6
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { shannonEntropyNormalized } from './entropy.js';
|
|
2
|
+
// Regular expressions for detecting suspicious keys and provider patterns
|
|
3
|
+
export const SUSPICIOUS_KEYS = /\b(pass(word)?|secret|token|apikey|api_key|key|auth|bearer|private|client_secret|access[_-]?token)\b/i;
|
|
4
|
+
// Regular expressions for detecting provider patterns
|
|
5
|
+
export const PROVIDER_PATTERNS = [
|
|
6
|
+
/\bAKIA[0-9A-Z]{16}\b/, // AWS access key id
|
|
7
|
+
/\bASIA[0-9A-Z]{16}\b/, // AWS temp key
|
|
8
|
+
/\bghp_[0-9A-Za-z]{30,}\b/, // GitHub token
|
|
9
|
+
/\bsk_live_[0-9a-zA-Z]{24,}\b/, // Stripe live secret
|
|
10
|
+
/\bsk_test_[0-9a-zA-Z]{24,}\b/, // Stripe test secret
|
|
11
|
+
/\bAIza[0-9A-Za-z\-_]{20,}\b/, // Google API key
|
|
12
|
+
/\bya29\.[0-9A-Za-z\-_]+\b/, // Google OAuth access token
|
|
13
|
+
/\b[A-Za-z0-9_-]{21}:[A-Za-z0-9_-]{140}\b/, // Firebase token
|
|
14
|
+
/\b0x[a-fA-F0-9]{40}\b/, // Ethereum address
|
|
15
|
+
/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/, // JWT token
|
|
16
|
+
/\bAC[0-9a-fA-F]{32}\b/, // Twilio Account SID
|
|
17
|
+
];
|
|
18
|
+
const LONG_LITERAL = /["'`]{1}([A-Za-z0-9+/_\-]{24,})["'`]{1}/g;
|
|
19
|
+
const HTTPS_PATTERN = /["'`](https?:\/\/(?!localhost)[^"'`]*)["'`]/g;
|
|
20
|
+
// List of harmless URL patterns to ignore
|
|
21
|
+
const HARMLESS_URLS = [
|
|
22
|
+
/https?:\/\/(www\.)?placeholder\.com/i,
|
|
23
|
+
/https?:\/\/(www\.)?example\.com/i,
|
|
24
|
+
/https?:\/\/127\.0\.0\.1(:\d+)?/i,
|
|
25
|
+
/http:\/\/www\.w3\.org\/2000\/svg/i,
|
|
26
|
+
/xmlns=["']http:\/\/www\.w3\.org\/2000\/svg["']/i, // SVG namespace
|
|
27
|
+
];
|
|
28
|
+
// Known harmless attribute keys commonly used in UI / analytics
|
|
29
|
+
const HARMLESS_ATTRIBUTE_KEYS = /\b(trackingId|trackingContext|data-testid|data-test|aria-label)\b/i;
|
|
30
|
+
// Checks if a line is an HTML text node
|
|
31
|
+
// Checks if a line is an HTML text node or tag
|
|
32
|
+
function isHtmlTextNode(line) {
|
|
33
|
+
const trimmed = line.trim();
|
|
34
|
+
// Empty line
|
|
35
|
+
if (!trimmed)
|
|
36
|
+
return false;
|
|
37
|
+
// Starts with <tag> and ends with </tag> with text inside
|
|
38
|
+
// OR is a self-contained HTML tag (even without closing tag on same line)
|
|
39
|
+
return ((/^<[^>]+>[^<]*<\/[^>]+>$/.test(trimmed) &&
|
|
40
|
+
!/=["'`][^"'`]*["'`]/.test(trimmed)) || // complete tag without suspicious assignment
|
|
41
|
+
/^<[a-z][a-z0-9-]*(?:\s+[a-z-]+(?:=["'][^"']*["'])?)*\s*\/?>$/i.test(trimmed) // opening or self-closing tag
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Determines the severity of a secret finding.
|
|
46
|
+
* @param kind 'pattern' | 'entropy'
|
|
47
|
+
* @param message The message describing the finding
|
|
48
|
+
* @param literalLength The length of the literal string (if applicable)
|
|
49
|
+
* @returns The severity level of the secret finding
|
|
50
|
+
*/
|
|
51
|
+
function determineSeverity(kind, message, literalLength) {
|
|
52
|
+
// HIGH: Known provider key patterns
|
|
53
|
+
if (message.includes('known provider key pattern')) {
|
|
54
|
+
return 'high';
|
|
55
|
+
}
|
|
56
|
+
// HIGH: Very high-entropy long strings
|
|
57
|
+
if (kind === 'entropy' && literalLength && literalLength >= 48) {
|
|
58
|
+
return 'high';
|
|
59
|
+
}
|
|
60
|
+
// MEDIUM: Password/secret/token patterns
|
|
61
|
+
if (message.includes('password/secret/token-like')) {
|
|
62
|
+
return 'medium';
|
|
63
|
+
}
|
|
64
|
+
// MEDIUM: Medium high-entropy strings
|
|
65
|
+
if (kind === 'entropy' && literalLength && literalLength >= 32) {
|
|
66
|
+
return 'medium';
|
|
67
|
+
}
|
|
68
|
+
// MEDIUM: HTTP URLs
|
|
69
|
+
if (message.includes('HTTP URL detected')) {
|
|
70
|
+
return 'medium';
|
|
71
|
+
}
|
|
72
|
+
// LOW: HTTPS URLs
|
|
73
|
+
if (message.includes('HTTPS URL detected')) {
|
|
74
|
+
return 'low';
|
|
75
|
+
}
|
|
76
|
+
// Default to medium if we can't determine
|
|
77
|
+
return 'medium';
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Checks if a line has an ignore comment
|
|
81
|
+
* fx: // dotenv-diff-ignore or /* dotenv-diff-ignore *\/ or <!-- dotenv-diff-ignore -->
|
|
82
|
+
* @param line - The line to check
|
|
83
|
+
* @returns True if the line should be ignored
|
|
84
|
+
*/
|
|
85
|
+
export function hasIgnoreComment(line) {
|
|
86
|
+
const normalized = line.trim();
|
|
87
|
+
// Allow mixed casing, extra spaces, and optional dashes
|
|
88
|
+
return (/\/\/.*dotenv[\s-]*diff[\s-]*ignore/i.test(normalized) ||
|
|
89
|
+
/\/\*.*dotenv[\s-]*diff[\s-]*ignore.*\*\//i.test(normalized) ||
|
|
90
|
+
/<!--.*dotenv[\s-]*diff[\s-]*ignore.*-->/i.test(normalized) ||
|
|
91
|
+
/\bdotenv[\s-]*diff[\s-]*ignore\b/i.test(normalized));
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Checks if a URL should be ignored based on ignoreUrls from config.
|
|
95
|
+
* @param url - The URL that might be a potential secret
|
|
96
|
+
* @param ignoreUrls - List of URLs to ignore (from config)
|
|
97
|
+
* @returns true if the URL matches any ignore pattern
|
|
98
|
+
*/
|
|
99
|
+
function ignoreUrlsMatch(url, ignoreUrls) {
|
|
100
|
+
if (!ignoreUrls?.length)
|
|
101
|
+
return false;
|
|
102
|
+
// case-insensitive substring match
|
|
103
|
+
return ignoreUrls.some((pattern) => url.toLowerCase().includes(pattern.toLowerCase()));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Checks if a string looks like a harmless literal.
|
|
107
|
+
* @param s - The string to check.
|
|
108
|
+
* @returns True if the string looks harmless, false otherwise.
|
|
109
|
+
*/
|
|
110
|
+
function looksHarmlessLiteral(s) {
|
|
111
|
+
return (/\S+@\S+/.test(s) || // emails
|
|
112
|
+
/^data:[a-z]+\/[a-z0-9.+-]+;base64,/i.test(s) || // data URIs
|
|
113
|
+
/^\.{0,2}\//.test(s) || // relative paths
|
|
114
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s) || // UUID
|
|
115
|
+
/^[0-9a-f]{32,128}$/i.test(s) || // MD5, SHA1, SHA256, etc.
|
|
116
|
+
/^[A-Za-z0-9+/_\-]{16,20}={0,2}$/.test(s) || // short base64
|
|
117
|
+
/^[A-Za-z0-9+/_\-]*(_PUBLIC|_PRIVATE|VITE_|NEXT_PUBLIC|VUE_)[A-Za-z0-9+/_\-]*={0,2}$/.test(s) || // env-like keys
|
|
118
|
+
/^[MmZzLlHhVvCcSsQqTtAa][0-9eE+.\- ,MmZzLlHhVvCcSsQqTtAa]*$/.test(s) || // SVG path data
|
|
119
|
+
/<svg[\s\S]*?>[\s\S]*?<\/svg>/i.test(s) || // SVG markup
|
|
120
|
+
HARMLESS_URLS.some((rx) => rx.test(s)) // Allowlisted URLs
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Checks if a line looks like a URL construction pattern.
|
|
125
|
+
* @param line - The line to check.
|
|
126
|
+
* @returns True if the line looks like URL construction, false otherwise.
|
|
127
|
+
*/
|
|
128
|
+
function looksLikeUrlConstruction(line) {
|
|
129
|
+
// Check for template literals or string concatenation that looks like URLs
|
|
130
|
+
return (
|
|
131
|
+
// Template literals with URL-like patterns
|
|
132
|
+
/=\s*`[^`]*\$\{[^}]+\}[^`]*\/[^`]*`/.test(line) ||
|
|
133
|
+
// String concatenation with slashes
|
|
134
|
+
/=\s*["'][^"']*\/[^"']*["']\s*\+/.test(line) ||
|
|
135
|
+
// Contains common URL patterns
|
|
136
|
+
/=\s*["'`][^"'`]*\/[^"'`]*(auth|api|login|redirect|callback|protocol)[^"'`]*\/[^"'`]*["'`]/.test(line) ||
|
|
137
|
+
// Keycloak-specific patterns
|
|
138
|
+
/realms\/.*\/protocol\/openid-connect/.test(line));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Checks if a file path is probably a test path.
|
|
142
|
+
* This is determined by looking for common test folder names and file extensions.
|
|
143
|
+
* @param p - The file path to check.
|
|
144
|
+
* @returns True if the file path is probably a test path, false otherwise.
|
|
145
|
+
*/
|
|
146
|
+
function isProbablyTestPath(p) {
|
|
147
|
+
return (/\b(__tests__|__mocks__|fixtures|sandbox|samples)\b/i.test(p) ||
|
|
148
|
+
/\.(spec|test)\.[jt]sx?$/.test(p));
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Checks if a string is a pure interpolation template.
|
|
152
|
+
* @param s - The string to check.
|
|
153
|
+
* @returns True if the string is a pure interpolation template, false otherwise.
|
|
154
|
+
*/
|
|
155
|
+
function isPureInterpolationTemplate(s) {
|
|
156
|
+
// Matches templates like `${a}`, `${a}:${b}`, `${a}|${b}|${c}`
|
|
157
|
+
// i.e. no meaningful static content
|
|
158
|
+
const withoutInterpolations = s.replace(/\$\{[^}]+\}/g, '');
|
|
159
|
+
return /^[\s:|,._-]*$/.test(withoutInterpolations);
|
|
160
|
+
}
|
|
161
|
+
// Threshold is the value between 0 and 1 that determines the sensitivity of the detection.
|
|
162
|
+
const DEFAULT_SECRET_THRESHOLD = 0.85;
|
|
163
|
+
/**
|
|
164
|
+
* Optimized for sveltekit and vite env accessors
|
|
165
|
+
* @param line - A line of code to check.
|
|
166
|
+
* @returns True if the line is an environment variable accessor, false otherwise.
|
|
167
|
+
*/
|
|
168
|
+
function isEnvAccessor(line) {
|
|
169
|
+
return /\b(process\.env|import\.meta\.env|\$env\/(static|dynamic)\/(public|private))\b/.test(line);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Detects secrets in the source code of a file.
|
|
173
|
+
* @param file - The file path to check.
|
|
174
|
+
* @param source - The source code to scan for secrets.
|
|
175
|
+
* @returns An array of secret findings.
|
|
176
|
+
*/
|
|
177
|
+
export function detectSecretsInSource(file, source, opts) {
|
|
178
|
+
const threshold = isProbablyTestPath(file) ? 0.95 : DEFAULT_SECRET_THRESHOLD;
|
|
179
|
+
const findings = [];
|
|
180
|
+
const lines = source.split(/\r?\n/);
|
|
181
|
+
let insideIgnoreBlock = false;
|
|
182
|
+
for (let i = 0; i < lines.length; i++) {
|
|
183
|
+
const lineNo = i + 1;
|
|
184
|
+
const line = lines[i] || '';
|
|
185
|
+
if (/<!--\s*dotenv[\s-]*diff[\s-]*ignore[\s-]*start\s*-->/i.test(line)) {
|
|
186
|
+
insideIgnoreBlock = true;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (/<!--\s*dotenv[\s-]*diff[\s-]*ignore[\s-]*end\s*-->/i.test(line)) {
|
|
190
|
+
insideIgnoreBlock = false;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
// Skip if inside ignore block
|
|
194
|
+
if (insideIgnoreBlock)
|
|
195
|
+
continue;
|
|
196
|
+
// Skip comments
|
|
197
|
+
if (/^\s*\/\//.test(line))
|
|
198
|
+
continue;
|
|
199
|
+
// Check if line has ignore comment
|
|
200
|
+
if (hasIgnoreComment(line))
|
|
201
|
+
continue;
|
|
202
|
+
// Check for HTTPS URLs
|
|
203
|
+
HTTPS_PATTERN.lastIndex = 0;
|
|
204
|
+
let httpsMatch;
|
|
205
|
+
while ((httpsMatch = HTTPS_PATTERN.exec(line))) {
|
|
206
|
+
const url = httpsMatch[1] || '';
|
|
207
|
+
if (url && !looksHarmlessLiteral(url)) {
|
|
208
|
+
if (ignoreUrlsMatch(url, opts?.ignoreUrls))
|
|
209
|
+
continue;
|
|
210
|
+
const protocol = url.startsWith('https') ? 'HTTPS' : 'HTTP';
|
|
211
|
+
findings.push({
|
|
212
|
+
file,
|
|
213
|
+
line: lineNo,
|
|
214
|
+
kind: 'pattern',
|
|
215
|
+
message: `${protocol} URL detected – consider moving to an environment variable`,
|
|
216
|
+
snippet: line.trim().slice(0, 180),
|
|
217
|
+
severity: protocol === 'HTTP' ? 'medium' : 'low',
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// 1) Suspicious key literal assignments
|
|
222
|
+
if (SUSPICIOUS_KEYS.test(line)) {
|
|
223
|
+
// Ignore known harmless UI / analytics attributes
|
|
224
|
+
if (HARMLESS_ATTRIBUTE_KEYS.test(line))
|
|
225
|
+
continue;
|
|
226
|
+
// Ignore HTML text nodes
|
|
227
|
+
if (isHtmlTextNode(line))
|
|
228
|
+
continue;
|
|
229
|
+
// Ignore if inside HTML tag content
|
|
230
|
+
if (/<[^>]*>.*<\/[^>]*>/.test(line.trim()))
|
|
231
|
+
continue;
|
|
232
|
+
const m = line.match(/=\s*["'`](.+?)["'`]/);
|
|
233
|
+
if (m &&
|
|
234
|
+
m[1] &&
|
|
235
|
+
!looksHarmlessLiteral(m[1]) &&
|
|
236
|
+
!looksLikeUrlConstruction(line) &&
|
|
237
|
+
m[1].length >= 12 &&
|
|
238
|
+
!isEnvAccessor(line) &&
|
|
239
|
+
!isPureInterpolationTemplate(m[1])) {
|
|
240
|
+
findings.push({
|
|
241
|
+
file,
|
|
242
|
+
line: lineNo,
|
|
243
|
+
kind: 'pattern',
|
|
244
|
+
message: 'matches password/secret/token-like literal assignment',
|
|
245
|
+
snippet: line.trim().slice(0, 180),
|
|
246
|
+
severity: 'medium',
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// 2) Provider patterns
|
|
251
|
+
for (const rx of PROVIDER_PATTERNS) {
|
|
252
|
+
if (rx.test(line)) {
|
|
253
|
+
findings.push({
|
|
254
|
+
file,
|
|
255
|
+
line: lineNo,
|
|
256
|
+
kind: 'pattern',
|
|
257
|
+
message: 'matches known provider key pattern',
|
|
258
|
+
snippet: line.trim().slice(0, 180),
|
|
259
|
+
severity: 'high',
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// 3) High-entropy long literals
|
|
264
|
+
LONG_LITERAL.lastIndex = 0;
|
|
265
|
+
let lm;
|
|
266
|
+
while ((lm = LONG_LITERAL.exec(line))) {
|
|
267
|
+
const literal = lm[1] || '';
|
|
268
|
+
if (looksHarmlessLiteral(literal))
|
|
269
|
+
continue;
|
|
270
|
+
if (literal.length < 32)
|
|
271
|
+
continue;
|
|
272
|
+
const ent = shannonEntropyNormalized(literal);
|
|
273
|
+
if (ent >= threshold) {
|
|
274
|
+
const message = `found high-entropy string (len ${literal.length}, H≈${ent.toFixed(2)})`;
|
|
275
|
+
findings.push({
|
|
276
|
+
file,
|
|
277
|
+
line: lineNo,
|
|
278
|
+
kind: 'entropy',
|
|
279
|
+
message,
|
|
280
|
+
snippet: line.trim().slice(0, 180),
|
|
281
|
+
severity: determineSeverity('entropy', message, literal.length),
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const uniqueFindings = findings.filter((f, idx, arr) => idx ===
|
|
287
|
+
arr.findIndex((other) => other.file === f.file &&
|
|
288
|
+
other.line === f.line &&
|
|
289
|
+
other.snippet === f.snippet));
|
|
290
|
+
return uniqueFindings;
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=secretDetectors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secretDetectors.js","sourceRoot":"","sources":["../../../../src/core/security/secretDetectors.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
1
|
export { parseEnvFile } from './core/parseEnv.js';
|
|
2
2
|
export { diffEnv } from './core/diffEnv.js';
|
|
3
|
-
const api = process.env.API_KEY;
|
|
4
|
-
const dbUrl = process.env.DATABASE_URL;
|
|
5
|
-
const fgKey = process.env.FGG_KE;
|
|
6
|
-
const fgKey2 = process.env.FGG_KE;
|
|
7
|
-
const secret = process.env.SECRET_TOKEN;
|
|
8
|
-
const secret2 = process.env.SECRET_TOKEN;
|
|
9
|
-
const secret3 = process.env.SECRET_TOKEN;
|
|
10
3
|
//# sourceMappingURL=index.js.map
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAmB,MAAM,mBAAmB,CAAC
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAmB,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ScanUsageOptions, ScanResult, ExitResult } from '../config/types.js';
|
|
2
|
+
interface FixContext {
|
|
3
|
+
fixApplied: boolean;
|
|
4
|
+
removedDuplicates: string[];
|
|
5
|
+
addedEnv: string[];
|
|
6
|
+
gitignoreUpdated: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Prints the scan result to the console.
|
|
10
|
+
* @param scanResult - The result of the scan.
|
|
11
|
+
* @param opts - The scan options.
|
|
12
|
+
* @param comparedAgainst - The file being compared against.
|
|
13
|
+
* @returns An object indicating whether to exit with an error.
|
|
14
|
+
*/
|
|
15
|
+
export declare function printScanResult(scanResult: ScanResult, opts: ScanUsageOptions, comparedAgainst: string, fixContext?: FixContext): ExitResult;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=printScanResult.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"printScanResult.d.ts","sourceRoot":"","sources":["../../../src/services/printScanResult.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACV,UAAU,EACX,MAAM,oBAAoB,CAAC;AAqB5B,UAAU,UAAU;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,gBAAgB,EACtB,eAAe,EAAE,MAAM,EACvB,UAAU,CAAC,EAAE,UAAU,GACtB,UAAU,CAkLZ"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { checkGitignoreStatus } from './git.js';
|
|
3
|
+
import { printGitignoreWarning } from '../ui/shared/printGitignore.js';
|
|
4
|
+
import { DEFAULT_ENV_FILE } from '../config/constants.js';
|
|
5
|
+
import { printHeader } from '../ui/scan/printHeader.js';
|
|
6
|
+
import { printStats } from '../ui/scan/printStats.js';
|
|
7
|
+
import { printMissing } from '../ui/scan/printMissing.js';
|
|
8
|
+
import { printUnused } from '../ui/scan/printUnused.js';
|
|
9
|
+
import { printDuplicates } from '../ui/shared/printDuplicates.js';
|
|
10
|
+
import { printSecrets } from '../ui/scan/printSecrets.js';
|
|
11
|
+
import { printSuccess } from '../ui/shared/printSuccess.js';
|
|
12
|
+
import { printStrictModeError } from '../ui/shared/printStrictModeError.js';
|
|
13
|
+
import { printFixTips } from '../ui/shared/printFixTips.js';
|
|
14
|
+
import { printAutoFix } from '../ui/shared/printAutoFix.js';
|
|
15
|
+
import { printFrameworkWarnings } from '../ui/scan/printFrameworkWarnings.js';
|
|
16
|
+
import { printExampleWarnings } from '../ui/scan/printExampleWarnings.js';
|
|
17
|
+
import { printConsolelogWarning } from '../ui/scan/printConsolelogWarning.js';
|
|
18
|
+
import { printUppercaseWarning } from '../ui/scan/printUppercaseWarning.js';
|
|
19
|
+
import { computeHealthScore } from '../core/computeHealthScore.js';
|
|
20
|
+
import { printHealthScore } from '../ui/scan/printHealthScore.js';
|
|
21
|
+
import { printExpireWarnings } from '../ui/scan/printExpireWarnings.js';
|
|
22
|
+
import { printInconsistentNamingWarning } from '../ui/scan/printInconsistentNamingWarning.js';
|
|
23
|
+
/**
|
|
24
|
+
* Prints the scan result to the console.
|
|
25
|
+
* @param scanResult - The result of the scan.
|
|
26
|
+
* @param opts - The scan options.
|
|
27
|
+
* @param comparedAgainst - The file being compared against.
|
|
28
|
+
* @returns An object indicating whether to exit with an error.
|
|
29
|
+
*/
|
|
30
|
+
export function printScanResult(scanResult, opts, comparedAgainst, fixContext) {
|
|
31
|
+
let exitWithError = false;
|
|
32
|
+
// Determine if output should be in JSON format
|
|
33
|
+
const isJson = opts.json ?? false;
|
|
34
|
+
printHeader(comparedAgainst);
|
|
35
|
+
// Show stats if requested
|
|
36
|
+
printStats(scanResult.stats, isJson, opts.showStats ?? true);
|
|
37
|
+
// Missing variables (used in code but not in env file)
|
|
38
|
+
if (printMissing(scanResult.missing, scanResult.used, comparedAgainst, opts.isCiMode ?? false, isJson)) {
|
|
39
|
+
exitWithError = true;
|
|
40
|
+
}
|
|
41
|
+
if (scanResult.frameworkWarnings && scanResult.frameworkWarnings.length > 0) {
|
|
42
|
+
printFrameworkWarnings(scanResult.frameworkWarnings, isJson);
|
|
43
|
+
}
|
|
44
|
+
if (scanResult.uppercaseWarnings && scanResult.uppercaseWarnings.length > 0) {
|
|
45
|
+
printUppercaseWarning(scanResult.uppercaseWarnings, comparedAgainst, isJson);
|
|
46
|
+
}
|
|
47
|
+
if (scanResult.inconsistentNamingWarnings &&
|
|
48
|
+
scanResult.inconsistentNamingWarnings.length > 0) {
|
|
49
|
+
printInconsistentNamingWarning(scanResult.inconsistentNamingWarnings, isJson);
|
|
50
|
+
}
|
|
51
|
+
printExampleWarnings(scanResult.exampleWarnings ?? [], isJson);
|
|
52
|
+
// Unused
|
|
53
|
+
printUnused(scanResult.unused, comparedAgainst, opts.showUnused ?? false, isJson);
|
|
54
|
+
// Duplicates
|
|
55
|
+
printDuplicates(comparedAgainst || DEFAULT_ENV_FILE, 'example file', scanResult.duplicates?.env ?? [], scanResult.duplicates?.example ?? [], isJson);
|
|
56
|
+
// Print potential secrets found
|
|
57
|
+
printSecrets(scanResult.secrets ?? [], isJson);
|
|
58
|
+
// Console log usage warning
|
|
59
|
+
printConsolelogWarning(scanResult.logged ?? [], isJson);
|
|
60
|
+
// Expiration warnings
|
|
61
|
+
printExpireWarnings(scanResult.expireWarnings ?? [], isJson);
|
|
62
|
+
// Check for high severity secrets - ALWAYS exit with error
|
|
63
|
+
const hasHighSeveritySecrets = (scanResult.secrets ?? []).some((s) => s.severity === 'high');
|
|
64
|
+
if (hasHighSeveritySecrets) {
|
|
65
|
+
exitWithError = true;
|
|
66
|
+
}
|
|
67
|
+
// Check for high severity example secrets - ALWAYS exit with error
|
|
68
|
+
const hasHighSeverityExampleSecrets = (scanResult.exampleWarnings ?? []).some((w) => w.severity === 'high');
|
|
69
|
+
if (hasHighSeverityExampleSecrets) {
|
|
70
|
+
exitWithError = true;
|
|
71
|
+
}
|
|
72
|
+
// Success message for env file comparison
|
|
73
|
+
if (comparedAgainst &&
|
|
74
|
+
scanResult.missing.length === 0 &&
|
|
75
|
+
(scanResult.secrets?.length ?? 0) === 0 &&
|
|
76
|
+
scanResult.used.length > 0) {
|
|
77
|
+
printSuccess(isJson, 'scan', comparedAgainst, scanResult.unused, opts.showUnused ?? true);
|
|
78
|
+
}
|
|
79
|
+
// Gitignore check
|
|
80
|
+
const gitignoreIssue = checkGitignoreStatus({
|
|
81
|
+
cwd: opts.cwd,
|
|
82
|
+
envFile: DEFAULT_ENV_FILE,
|
|
83
|
+
});
|
|
84
|
+
if (gitignoreIssue && !opts.json) {
|
|
85
|
+
printGitignoreWarning({
|
|
86
|
+
envFile: DEFAULT_ENV_FILE,
|
|
87
|
+
reason: gitignoreIssue.reason,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
const hasGitignoreIssue = gitignoreIssue !== null;
|
|
91
|
+
if (opts.strict) {
|
|
92
|
+
const exit = printStrictModeError({
|
|
93
|
+
unused: scanResult.unused.length,
|
|
94
|
+
duplicatesEnv: scanResult.duplicates?.env?.length ?? 0,
|
|
95
|
+
duplicatesEx: scanResult.duplicates?.example?.length ?? 0,
|
|
96
|
+
secrets: scanResult.secrets?.length ?? 0,
|
|
97
|
+
exampleSecrets: scanResult.exampleWarnings?.length ?? 0,
|
|
98
|
+
hasGitignoreIssue,
|
|
99
|
+
frameworkWarnings: scanResult.frameworkWarnings?.length ?? 0,
|
|
100
|
+
logged: scanResult.logged?.length ?? 0,
|
|
101
|
+
uppercaseWarnings: scanResult.uppercaseWarnings?.length ?? 0,
|
|
102
|
+
expireWarnings: scanResult.expireWarnings?.length ?? 0,
|
|
103
|
+
inconsistentNamingWarnings: scanResult.inconsistentNamingWarnings?.length ?? 0,
|
|
104
|
+
}, isJson);
|
|
105
|
+
if (exit)
|
|
106
|
+
exitWithError = true;
|
|
107
|
+
}
|
|
108
|
+
if (opts.fix && fixContext) {
|
|
109
|
+
printAutoFix(fixContext.fixApplied, {
|
|
110
|
+
removedDuplicates: fixContext.removedDuplicates,
|
|
111
|
+
addedEnv: fixContext.addedEnv,
|
|
112
|
+
addedExample: opts.examplePath ? fixContext.addedEnv : [],
|
|
113
|
+
}, comparedAgainst || DEFAULT_ENV_FILE, opts.examplePath ? path.basename(opts.examplePath) : 'example file', isJson, fixContext.gitignoreUpdated);
|
|
114
|
+
}
|
|
115
|
+
// Health score
|
|
116
|
+
const score = computeHealthScore(scanResult);
|
|
117
|
+
printHealthScore(score);
|
|
118
|
+
// Filtered results for fix tips
|
|
119
|
+
printFixTips({
|
|
120
|
+
missing: scanResult.missing,
|
|
121
|
+
duplicatesEnv: scanResult.duplicates?.env ?? [],
|
|
122
|
+
duplicatesEx: scanResult.duplicates?.example ?? [],
|
|
123
|
+
gitignoreIssue: hasGitignoreIssue ? { reason: 'not-ignored' } : null,
|
|
124
|
+
}, hasGitignoreIssue, isJson, opts.fix ?? false);
|
|
125
|
+
return { exitWithError };
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=printScanResult.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"printScanResult.js","sourceRoot":"","sources":["../../../src/services/printScanResult.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ScanOptions, ScanResult } from '../config/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Scans the codebase for environment variable usage based on the provided options.
|
|
4
|
+
* @param opts - Options for scanning the codebase.
|
|
5
|
+
* @returns A promise that resolves to the scan result containing used, missing, and unused variables.
|
|
6
|
+
*/
|
|
7
|
+
export declare function scanCodebase(opts: ScanOptions): Promise<ScanResult>;
|
|
8
|
+
//# sourceMappingURL=scanCodebase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanCodebase.d.ts","sourceRoot":"","sources":["../../../src/services/scanCodebase.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAY,WAAW,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAU5E;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAsEzE"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { detectSecretsInSource, } from '../core/security/secretDetectors.js';
|
|
4
|
+
import { DEFAULT_EXCLUDE_PATTERNS } from '../core/patterns.js';
|
|
5
|
+
import { scanFile } from '../core/scanFile.js';
|
|
6
|
+
import { findFiles } from './fileWalker.js';
|
|
7
|
+
import { printProgress } from '../ui/scan/printProgress.js';
|
|
8
|
+
/**
|
|
9
|
+
* Scans the codebase for environment variable usage based on the provided options.
|
|
10
|
+
* @param opts - Options for scanning the codebase.
|
|
11
|
+
* @returns A promise that resolves to the scan result containing used, missing, and unused variables.
|
|
12
|
+
*/
|
|
13
|
+
export async function scanCodebase(opts) {
|
|
14
|
+
const files = await findFiles(opts.cwd, {
|
|
15
|
+
include: opts.include,
|
|
16
|
+
exclude: [...DEFAULT_EXCLUDE_PATTERNS, ...opts.exclude],
|
|
17
|
+
...(opts.files ? { files: opts.files } : {}), // Pass files option
|
|
18
|
+
});
|
|
19
|
+
const allUsages = [];
|
|
20
|
+
let filesScanned = 0;
|
|
21
|
+
const allSecrets = [];
|
|
22
|
+
const fileContentMap = new Map();
|
|
23
|
+
for (const filePath of files) {
|
|
24
|
+
const content = await safeReadFile(filePath);
|
|
25
|
+
if (!content)
|
|
26
|
+
continue;
|
|
27
|
+
// Scan the file for environment variable usages
|
|
28
|
+
const fileUsages = scanFile(filePath, content, opts);
|
|
29
|
+
allUsages.push(...fileUsages);
|
|
30
|
+
// Store file content for later use (e.g., framework validation 'use client')
|
|
31
|
+
const relativePath = path.relative(opts.cwd, filePath);
|
|
32
|
+
fileContentMap.set(relativePath, content);
|
|
33
|
+
// Detect secrets in the file content
|
|
34
|
+
const secrets = safeDetectSecrets(relativePath, content, opts);
|
|
35
|
+
if (secrets.length)
|
|
36
|
+
allSecrets.push(...secrets);
|
|
37
|
+
// Count successfully scanned files
|
|
38
|
+
filesScanned++;
|
|
39
|
+
if (shouldPrintProgress(filesScanned, files.length)) {
|
|
40
|
+
printProgress({
|
|
41
|
+
isJson: opts.json,
|
|
42
|
+
current: filesScanned,
|
|
43
|
+
total: files.length,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Filter out ignored variables
|
|
48
|
+
const filteredUsages = allUsages.filter((usage) => !opts.ignore.includes(usage.variable) &&
|
|
49
|
+
!opts.ignoreRegex.some((regex) => regex.test(usage.variable)));
|
|
50
|
+
const uniqueVariables = [...new Set(filteredUsages.map((u) => u.variable))];
|
|
51
|
+
const loggedVariables = filteredUsages.filter((u) => u.isLogged);
|
|
52
|
+
return {
|
|
53
|
+
used: filteredUsages,
|
|
54
|
+
missing: [],
|
|
55
|
+
unused: [],
|
|
56
|
+
secrets: allSecrets,
|
|
57
|
+
stats: {
|
|
58
|
+
filesScanned,
|
|
59
|
+
totalUsages: filteredUsages.length,
|
|
60
|
+
uniqueVariables: uniqueVariables.length,
|
|
61
|
+
warningsCount: 0,
|
|
62
|
+
duration: 0,
|
|
63
|
+
},
|
|
64
|
+
duplicates: {
|
|
65
|
+
env: [],
|
|
66
|
+
example: [],
|
|
67
|
+
},
|
|
68
|
+
logged: loggedVariables,
|
|
69
|
+
fileContentMap,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Detects secrets in the given file content if secret detection is enabled.
|
|
74
|
+
* @param relativePath - The relative path of the file being scanned.
|
|
75
|
+
* @param content - The content of the file.
|
|
76
|
+
* @param opts - The scan options.
|
|
77
|
+
* @returns An array of secret findings.
|
|
78
|
+
*/
|
|
79
|
+
function safeDetectSecrets(relativePath, content, opts) {
|
|
80
|
+
if (!opts.secrets)
|
|
81
|
+
return [];
|
|
82
|
+
try {
|
|
83
|
+
return detectSecretsInSource(relativePath, content, opts).filter((s) => s.severity !== 'low');
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Safely reads a file and returns its content or null if reading fails.
|
|
91
|
+
* @param filePath - The path to the file to read.
|
|
92
|
+
* @returns The file content as a string, or null if an error occurs.
|
|
93
|
+
*/
|
|
94
|
+
async function safeReadFile(filePath) {
|
|
95
|
+
try {
|
|
96
|
+
return await fs.readFile(filePath, 'utf-8');
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** * Determines whether to print progress based on the number of files scanned.
|
|
103
|
+
* @param scanned - The number of files scanned so far.
|
|
104
|
+
* @param total - The total number of files to scan.
|
|
105
|
+
* @returns True if progress should be printed, false otherwise.
|
|
106
|
+
*/
|
|
107
|
+
function shouldPrintProgress(scanned, total) {
|
|
108
|
+
return scanned === 1 || scanned % 10 === 0 || scanned === total;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=scanCodebase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanCodebase.js","sourceRoot":"","sources":["../../../src/services/scanCodebase.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"printConsolelogWarning.d.ts","sourceRoot":"","sources":["../../../../src/ui/scan/printConsolelogWarning.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,uBAAuB,CAAC;AAGtE;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,QAAQ,EAAE,EAClB,IAAI,EAAE,OAAO,GACZ,OAAO,
|
|
1
|
+
{"version":3,"file":"printConsolelogWarning.d.ts","sourceRoot":"","sources":["../../../../src/ui/scan/printConsolelogWarning.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,uBAAuB,CAAC;AAGtE;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,QAAQ,EAAE,EAClB,IAAI,EAAE,OAAO,GACZ,OAAO,CAyCT"}
|
|
@@ -13,7 +13,6 @@ export function printConsolelogWarning(logged, json) {
|
|
|
13
13
|
if (!logged || logged.length === 0)
|
|
14
14
|
return false;
|
|
15
15
|
console.log(chalk.yellow(`⚠️ Environment variables logged to console:`));
|
|
16
|
-
// Group by variable name
|
|
17
16
|
const grouped = logged.reduce((acc, entry) => {
|
|
18
17
|
if (!acc[entry.variable])
|
|
19
18
|
acc[entry.variable] = [];
|
|
@@ -22,14 +21,16 @@ export function printConsolelogWarning(logged, json) {
|
|
|
22
21
|
}, {});
|
|
23
22
|
for (const [variable, usages] of Object.entries(grouped)) {
|
|
24
23
|
console.log(chalk.yellow(` - ${variable}`));
|
|
24
|
+
// Deduplicate by file + line (unique locations)
|
|
25
|
+
const uniqueUsages = Array.from(new Map(usages.map((u) => [`${u.file}:${u.line}`, u])).values());
|
|
25
26
|
const maxShow = 3;
|
|
26
|
-
|
|
27
|
+
uniqueUsages.slice(0, maxShow).forEach((usage) => {
|
|
27
28
|
const normalizedFile = normalizePath(usage.file);
|
|
28
29
|
console.log(chalk.yellow.dim(` Logged at: ${normalizedFile}:${usage.line}`));
|
|
29
30
|
console.log(chalk.gray(` ${usage.context.trim()}`));
|
|
30
31
|
});
|
|
31
|
-
if (
|
|
32
|
-
console.log(chalk.gray(` ... and ${
|
|
32
|
+
if (uniqueUsages.length > maxShow) {
|
|
33
|
+
console.log(chalk.gray(` ... and ${uniqueUsages.length - maxShow} more locations`));
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
console.log();
|