Skip to content

Commit 13f4df6

Browse files
authored
fix: added to default exclude patterns (#359)
* fix: added to default exclude patterns * chore: tests
1 parent c142351 commit 13f4df6

File tree

7 files changed

+200
-36
lines changed

7 files changed

+200
-36
lines changed

.changeset/chilly-lands-dance.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'dotenv-diff': patch
3+
---
4+
5+
added more patterns to DEFAULT_EXCLUDE_PATTERNS

docs/configuration_and_flags.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,7 @@ Usage in the configuration file:
363363
### `--exclude-files <patterns>`
364364

365365
Specify a comma-separated list of file patterns to exclude from scanning.
366-
These patterns are added to the default exclude patterns (like `node_modules`, `dist`, etc.).
367-
Useful when you want to skip specific files or directories that shouldn't be scanned.
366+
These patterns are added on top of the built-in default exclude patterns. This is useful when you want to skip additional files or directories that should not be scanned in your project.
368367

369368
Example usage:
370369

@@ -380,6 +379,50 @@ Usage in the configuration file:
380379
}
381380
```
382381

382+
dotenv-diff already excludes the following paths by default:
383+
384+
```bash
385+
[
386+
'node_modules',
387+
'.sveltekit',
388+
'.svelte-kit',
389+
'_actions',
390+
'dist',
391+
'build',
392+
'.next',
393+
'.nuxt',
394+
'coverage',
395+
'.git',
396+
'.vscode',
397+
'.idea',
398+
'.test.',
399+
'.spec.',
400+
'__tests__',
401+
'__mocks__',
402+
'test',
403+
'tests',
404+
'fixtures',
405+
'fixture',
406+
'examples',
407+
'example',
408+
'samples',
409+
'sandbox',
410+
'.turbo',
411+
'.cache',
412+
'.output',
413+
'.vercel',
414+
'.yarn',
415+
'.pnpm-store',
416+
'.parcel-cache',
417+
'.rollup.cache',
418+
'.DS_Store'
419+
]
420+
```
421+
422+
Your custom --exclude-files patterns are appended to that list.
423+
424+
If you later want to scan files from one of the default excluded paths, use `--include-files` or `--files` to explicitly include them.
425+
383426
## Display Options
384427

385428
### `--show-unused`

packages/cli/src/core/scan/patterns.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,31 @@ export const DEFAULT_EXCLUDE_PATTERNS = [
163163
'.git',
164164
'.vscode',
165165
'.idea',
166+
167+
// Tests
166168
'.test.',
167169
'.spec.',
168170
'__tests__',
169171
'__mocks__',
172+
173+
// Common noisy paths
174+
'test',
175+
'tests',
176+
'fixtures',
177+
'fixture',
178+
'examples',
179+
'example',
180+
'samples',
181+
'sandbox',
182+
183+
// Generated / vendored / caches
184+
'.turbo',
185+
'.cache',
186+
'.output',
187+
'.vercel',
188+
'.yarn',
189+
'.pnpm-store',
190+
'.parcel-cache',
191+
'.rollup.cache',
192+
'.DS_Store',
170193
];

packages/cli/src/services/fileWalker.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ export async function findFiles(
4040
? [...defaultPatterns, ...opts.include]
4141
: defaultPatterns;
4242
const includePatterns = rawInclude.flatMap(expandBraceSets);
43+
const explicitIncludePatterns = (opts.include ?? []).flatMap(expandBraceSets);
44+
const explicitIncludeBases = explicitIncludePatterns
45+
.map((pattern) => {
46+
const normalized = pattern.replace(/\\/g, '/');
47+
const idx = normalized.search(/[*?\[\]{}]/);
48+
const base = idx === -1 ? normalized : normalized.slice(0, idx);
49+
return base.replace(/\/$/, '');
50+
})
51+
.filter(Boolean);
4352

4453
const files: string[] = [];
4554
const walked = new Set<string>();
@@ -76,9 +85,23 @@ export async function findFiles(
7685
for (const entry of entries) {
7786
const fullPath = path.join(startDir, entry.name);
7887
const relativeToRoot = path.relative(rootDir, fullPath);
88+
const normalizedRelative = relativeToRoot.replace(/\\/g, '/');
89+
const explicitlyIncluded =
90+
explicitIncludePatterns.length > 0 &&
91+
shouldInclude(entry.name, relativeToRoot, explicitIncludePatterns);
92+
const includedDirectoryRoot =
93+
entry.isDirectory() &&
94+
explicitIncludeBases.some(
95+
(base) =>
96+
normalizedRelative === base ||
97+
normalizedRelative.startsWith(`${base}/`) ||
98+
base.startsWith(`${normalizedRelative}/`),
99+
);
79100

80101
// Exclude checks should use path relative to *rootDir* (keeps existing semantics)
81102
if (
103+
!explicitlyIncluded &&
104+
!includedDirectoryRoot &&
82105
shouldExclude(entry.name, relativeToRoot, [
83106
...DEFAULT_EXCLUDE_PATTERNS,
84107
...(opts.exclude ?? []),

packages/cli/test/e2e/frameworks/cli.nextJs.e2e.test.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ describe('Next.js environment variable usage rules', () => {
5757
}`,
5858
);
5959

60-
fs.writeFileSync(path.join(cwd, '.env'), `SECRET_SERVER_KEY=ok`);
60+
fs.writeFileSync(path.join(cwd, '.env'), 'SECRET_SERVER_KEY=ok');
6161

6262
const res = runCli(cwd, ['--scan-usage']);
6363

@@ -79,7 +79,7 @@ describe('Next.js environment variable usage rules', () => {
7979
console.log(process.env.NEXT_PUBLIC_IMAGE_BASE);`,
8080
);
8181

82-
fs.writeFileSync(path.join(cwd, '.env'), `NEXT_PUBLIC_IMAGE_BASE=1`);
82+
fs.writeFileSync(path.join(cwd, '.env'), 'NEXT_PUBLIC_IMAGE_BASE=1');
8383

8484
const res = runCli(cwd, ['--scan-usage']);
8585

@@ -98,7 +98,7 @@ console.log(process.env.NEXT_PUBLIC_IMAGE_BASE);`,
9898
console.log(process.env.SECRET_TOKEN);`,
9999
);
100100

101-
fs.writeFileSync(path.join(cwd, '.env'), `SECRET_TOKEN=1`);
101+
fs.writeFileSync(path.join(cwd, '.env'), 'SECRET_TOKEN=1');
102102

103103
const res = runCli(cwd, ['--scan-usage']);
104104

@@ -111,17 +111,17 @@ console.log(process.env.SECRET_TOKEN);`,
111111
const cwd = tmpDir();
112112
makeNextProject(cwd);
113113

114-
fs.mkdirSync(path.join(cwd, 'app/api/test'), { recursive: true });
114+
fs.mkdirSync(path.join(cwd, 'app/api/code'), { recursive: true });
115115
fs.writeFileSync(
116-
path.join(cwd, 'app/api/test/route.ts'),
116+
path.join(cwd, 'app/api/code/route.ts'),
117117
`export async function GET() {
118118
process.env.NEXT_PUBLIC_SECRET_PASSWORD;
119119
}`,
120120
);
121121

122122
fs.writeFileSync(
123123
path.join(cwd, '.env'),
124-
`NEXT_PUBLIC_SECRET_PASSWORD=secret123`,
124+
'NEXT_PUBLIC_SECRET_PASSWORD=secret123',
125125
);
126126
const res = runCli(cwd, ['--scan-usage', '--json']);
127127

@@ -141,7 +141,7 @@ console.log(process.env.SECRET_TOKEN);`,
141141
expect(warning.reason).toContain(
142142
'Potential sensitive environment variable exposed to the browser',
143143
);
144-
expect(warning.file).toContain('app/api/test/route.ts');
144+
expect(warning.file).toContain('app/api/code/route.ts');
145145
expect(warning.line).toBeGreaterThan(0);
146146
});
147147

@@ -228,7 +228,7 @@ API_ENDPOINT=api`,
228228
}`,
229229
);
230230

231-
fs.writeFileSync(path.join(cwd, '.env'), `DATABASE_URL=postgresql://...`);
231+
fs.writeFileSync(path.join(cwd, '.env'), 'DATABASE_URL=postgresql://...');
232232

233233
const res = runCli(cwd, ['--scan-usage']);
234234

@@ -249,7 +249,7 @@ API_ENDPOINT=api`,
249249
}`,
250250
);
251251

252-
fs.writeFileSync(path.join(cwd, '.env'), `DATABASE_URL=db`);
252+
fs.writeFileSync(path.join(cwd, '.env'), 'DATABASE_URL=db');
253253

254254
const res = runCli(cwd, ['--scan-usage']);
255255

@@ -262,13 +262,13 @@ API_ENDPOINT=api`,
262262

263263
fs.mkdirSync(path.join(cwd, 'pages/api'), { recursive: true });
264264
fs.writeFileSync(
265-
path.join(cwd, 'pages/api/test.ts'),
265+
path.join(cwd, 'pages/api/code.ts'),
266266
`export default function handler() {
267267
console.log(process.env.SECRET_KEY);
268268
}`,
269269
);
270270

271-
fs.writeFileSync(path.join(cwd, '.env'), `SECRET_KEY=ok`);
271+
fs.writeFileSync(path.join(cwd, '.env'), 'SECRET_KEY=ok');
272272

273273
const res = runCli(cwd, ['--scan-usage']);
274274

@@ -288,7 +288,7 @@ API_ENDPOINT=api`,
288288
}`,
289289
);
290290

291-
fs.writeFileSync(path.join(cwd, '.env'), `SECRET_KEY=ok`);
291+
fs.writeFileSync(path.join(cwd, '.env'), 'SECRET_KEY=ok');
292292

293293
const res = runCli(cwd, ['--scan-usage']);
294294

packages/cli/test/e2e/frameworks/cli.sveltekit.e2e.test.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ describe('SvelteKit environment variable usage rules', () => {
4747

4848
fs.writeFileSync(
4949
path.join(cwd, 'src/routes/+page.ts'),
50-
`console.log(import.meta.env.PUBLIC_URL);`,
50+
'console.log(import.meta.env.PUBLIC_URL);',
5151
);
5252

53-
fs.writeFileSync(path.join(cwd, '.env'), `PUBLIC_URL=123`);
53+
fs.writeFileSync(path.join(cwd, '.env'), 'PUBLIC_URL=123');
5454

5555
const res = runCli(cwd, ['--scan-usage']);
5656

@@ -65,10 +65,10 @@ describe('SvelteKit environment variable usage rules', () => {
6565

6666
fs.writeFileSync(
6767
path.join(cwd, 'src/routes/+page.ts'),
68-
`console.log(import.meta.env.VITE_PUBLIC_URL);`,
68+
'console.log(import.meta.env.VITE_PUBLIC_URL);',
6969
);
7070

71-
fs.writeFileSync(path.join(cwd, '.env'), `VITE_PUBLIC_URL=123`);
71+
fs.writeFileSync(path.join(cwd, '.env'), 'VITE_PUBLIC_URL=123');
7272

7373
const res = runCli(cwd, ['--scan-usage']);
7474

@@ -82,10 +82,10 @@ describe('SvelteKit environment variable usage rules', () => {
8282

8383
fs.writeFileSync(
8484
path.join(cwd, 'src/index.ts'),
85-
`console.log(process.env.VITE_SECRET);`,
85+
'console.log(process.env.VITE_SECRET);',
8686
);
8787

88-
fs.writeFileSync(path.join(cwd, '.env'), `VITE_SECRET=123`);
88+
fs.writeFileSync(path.join(cwd, '.env'), 'VITE_SECRET=123');
8989

9090
const res = runCli(cwd, ['--scan-usage']);
9191

@@ -99,7 +99,7 @@ describe('SvelteKit environment variable usage rules', () => {
9999

100100
fs.writeFileSync(
101101
path.join(cwd, 'src/app.ts'),
102-
`import { VITE_PUBLIC } from '$env/static/public';`,
102+
'import { VITE_PUBLIC } from \'$env/static/public\';',
103103
);
104104

105105
fs.writeFileSync(path.join(cwd, '.env'), 'VITE_PUBLIC=123');
@@ -135,7 +135,7 @@ describe('SvelteKit environment variable usage rules', () => {
135135

136136
fs.writeFileSync(
137137
path.join(cwd, 'src/routes/+page.svelte'),
138-
`import { SECRET_KEY } from '$env/static/private';`,
138+
'import { SECRET_KEY } from \'$env/static/private\';',
139139
);
140140

141141
fs.writeFileSync(path.join(cwd, '.env'), 'SECRET_KEY=123');
@@ -174,8 +174,8 @@ describe('SvelteKit environment variable usage rules', () => {
174174
makeSvelteKitProject(cwd);
175175

176176
fs.writeFileSync(
177-
path.join(cwd, 'src/test.ts'),
178-
`import { PUBLIC_TOKEN } from '$env/static/private';`,
177+
path.join(cwd, 'src/svelteFile.ts'),
178+
'import { PUBLIC_TOKEN } from \'$env/static/private\';',
179179
);
180180

181181
fs.writeFileSync(path.join(cwd, '.env'), 'PUBLIC_TOKEN=123');
@@ -197,7 +197,7 @@ const url2 = import.meta.env.PUBLIC_URL;
197197
const url3 = import.meta.env.PUBLIC_URL;`,
198198
);
199199

200-
fs.writeFileSync(path.join(cwd, '.env'), `PUBLIC_URL=123`);
200+
fs.writeFileSync(path.join(cwd, '.env'), 'PUBLIC_URL=123');
201201

202202
const res = runCli(cwd, ['--scan-usage']);
203203

@@ -212,10 +212,10 @@ const url3 = import.meta.env.PUBLIC_URL;`,
212212

213213
fs.writeFileSync(
214214
path.join(cwd, 'src/routes/+page.ts'),
215-
`console.log(import.meta.env.PUBLIC_URL);`,
215+
'console.log(import.meta.env.PUBLIC_URL);',
216216
);
217217

218-
fs.writeFileSync(path.join(cwd, '.env'), `PUBLIC_URL=123`);
218+
fs.writeFileSync(path.join(cwd, '.env'), 'PUBLIC_URL=123');
219219

220220
const res = runCli(cwd, ['--scan-usage', '--strict']);
221221

@@ -230,10 +230,10 @@ const url3 = import.meta.env.PUBLIC_URL;`,
230230

231231
fs.writeFileSync(
232232
path.join(cwd, 'src/routes/+page.server.ts'),
233-
`console.log(import.meta.env.SECRET_KEY);`,
233+
'console.log(import.meta.env.SECRET_KEY);',
234234
);
235235

236-
fs.writeFileSync(path.join(cwd, '.env'), `SECRET_KEY=123`);
236+
fs.writeFileSync(path.join(cwd, '.env'), 'SECRET_KEY=123');
237237

238238
const res = runCli(cwd, ['--scan-usage']);
239239

@@ -247,10 +247,10 @@ const url3 = import.meta.env.PUBLIC_URL;`,
247247

248248
fs.writeFileSync(
249249
path.join(cwd, 'src/routes/+server.ts'),
250-
`console.log(import.meta.env.API_KEY);`,
250+
'console.log(import.meta.env.API_KEY);',
251251
);
252252

253-
fs.writeFileSync(path.join(cwd, '.env'), `API_KEY=123`);
253+
fs.writeFileSync(path.join(cwd, '.env'), 'API_KEY=123');
254254

255255
const res = runCli(cwd, ['--scan-usage']);
256256

@@ -302,7 +302,7 @@ const url3 = import.meta.env.PUBLIC_URL;`,
302302

303303
fs.writeFileSync(
304304
path.join(cwd, 'src/routes/+page.svelte'),
305-
`import SECRET_KEY from '$env/static/private';`,
305+
'import SECRET_KEY from \'$env/static/private\';',
306306
);
307307

308308
fs.writeFileSync(path.join(cwd, '.env'), 'SECRET_KEY=123');
@@ -516,9 +516,9 @@ const url3 = import.meta.env.PUBLIC_URL;`,
516516

517517
fs.writeFileSync(
518518
path.join(cwd, 'src/+server.ts'),
519-
`console.log(process.env.SECRET_KEY);`,
519+
'console.log(process.env.SECRET_KEY);',
520520
);
521-
fs.writeFileSync(path.join(cwd, '.env'), `SECRET_KEY=123`);
521+
fs.writeFileSync(path.join(cwd, '.env'), 'SECRET_KEY=123');
522522

523523
const res = runCli(cwd, ['--scan-usage']);
524524

@@ -534,9 +534,9 @@ const url3 = import.meta.env.PUBLIC_URL;`,
534534

535535
fs.writeFileSync(
536536
path.join(cwd, 'src/hooks.server.ts'),
537-
`console.log(process.env.SECRET_KEY);`,
537+
'console.log(process.env.SECRET_KEY);',
538538
);
539-
fs.writeFileSync(path.join(cwd, '.env'), `SECRET_KEY=123`);
539+
fs.writeFileSync(path.join(cwd, '.env'), 'SECRET_KEY=123');
540540

541541
const res = runCli(cwd, ['--scan-usage']);
542542

0 commit comments

Comments
 (0)