Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/smoke-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,16 @@ jobs:
exit 1
fi

# Plain `npm install` on purpose: this checks the tarball installs the way
# it does for a user, so it cannot be locked with `npm ci`. TypeScript is
# not installed here: the type check uses the repo's tsc, pinned by
# pnpm-lock.yaml, to keep unpinned downloads to the package's own deps.
- name: Install tarball into empty project
working-directory: ${{ runner.temp }}/smoke
run: |
npm init -y > /dev/null
npm pkg set type=module
npm install --no-audit --no-fund ./dotenv-diff-*.tgz typescript
npm install --no-audit --no-fund ./dotenv-diff-*.tgz

- name: Run CLI
working-directory: ${{ runner.temp }}/smoke
Expand Down Expand Up @@ -134,5 +138,5 @@ jobs:
const result: DiffResult = diffEnv(parseEnvContent('A=1'), {});
export const missing: string[] = result.missing;
EOF
npx --no-install tsc -p tsconfig.json
node "$GITHUB_WORKSPACE/node_modules/typescript/bin/tsc" -p tsconfig.json
echo "Types OK"
28 changes: 1 addition & 27 deletions packages/cli/src/commands/scanUsage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { processComparisonFile } from '../services/processComparisonFile.js';
import { printComparisonError } from '../ui/scan/printComparisonError.js';
import { skipCommentedUsages } from '../core/scan/skipCommentedUsages.js';
import { frameworkValidator } from '../core/frameworks/frameworkValidator.js';
import { detectSecretsInExample } from '../core/security/exampleSecretDetector.js';
import { checkGitignoreStatus } from '../services/git.js';
import { promptNoEnvScenario } from './prompts/promptNoEnvScenario.js';
import {
Expand Down Expand Up @@ -109,36 +108,11 @@ export async function scanUsage(opts: ScanUsageOptions): Promise<ExitResult> {
if (exit) return { exitWithError: true };
} else {
scanResult = result.scanResult;
comparedAgainst = result.comparedAgainst;
if (result.exampleFile) {
scanResult.exampleFile = result.exampleFile;
}
comparedAgainst = compareFile.name;
fixApplied = result.fix.fixApplied;
removedDuplicates = result.fix.removedDuplicates;
fixedKeys = result.fix.addedEnv;
gitignoreUpdated = result.fix.gitignoreUpdated;
if (result.uppercaseWarnings) {
scanResult.uppercaseWarnings = result.uppercaseWarnings;
}
if (result.expireWarnings) {
scanResult.expireWarnings = result.expireWarnings;
}
if (result.inconsistentNamingWarnings) {
scanResult.inconsistentNamingWarnings =
result.inconsistentNamingWarnings;
}
if (result.commentWarnings) {
scanResult.commentWarnings = result.commentWarnings;
}
if (result.driftWarnings) {
scanResult.driftWarnings = result.driftWarnings;
}
if (result.exampleFull) {
scanResult.exampleWarnings = detectSecretsInExample(
result.exampleFull,
result.exampleFile,
);
}
}
}

Expand Down
17 changes: 17 additions & 0 deletions packages/cli/src/core/detectUppercaseKeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { UppercaseWarning } from '../config/types.js';
import { toUpperSnakeCase } from './helpers/toUpperSnakeCase.js';

/** A key in UPPER_SNAKE_CASE: uppercase letters, digits and underscores. */
const UPPER_SNAKE_CASE = /^[A-Z0-9_]+$/;

/**
* Detects environment variable keys that are not in UPPER_SNAKE_CASE.
* For example: `apiKey` → suggests `API_KEY`.
* @param keys - Array of environment variable keys to analyze
* @returns Array of uppercase warnings, each with a suggested key
*/
export function detectUppercaseKeys(keys: string[]): UppercaseWarning[] {
return keys
.filter((key) => !UPPER_SNAKE_CASE.test(key))
.map((key) => ({ key, suggestion: toUpperSnakeCase(key) }));
}
30 changes: 30 additions & 0 deletions packages/cli/src/core/scan/excludeOptionalKeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { ScanResult } from '../../config/types.js';

/**
* Removes keys marked `@optional` from the missing keys of a scan result.
*
* An optional key may be left out of the env file entirely — that is what the
* annotation means — so it must not be reported as missing. The typo
* suggestions derived from those keys go too.
* @param scanResult - The result of the scan.
* @param optionalKeys - Keys marked `@optional` in the example file.
* @returns The scan result without the optional keys.
*/
export function excludeOptionalKeys(
scanResult: ScanResult,
optionalKeys: ReadonlySet<string>,
): ScanResult {
if (optionalKeys.size === 0) return scanResult;

const isRequired = (key: string) => !optionalKeys.has(key);

return {
...scanResult,
missing: scanResult.missing.filter(isRequired),
...(scanResult.suggestions
? {
suggestions: scanResult.suggestions.filter((s) => isRequired(s.key)),
}
: {}),
};
}
Loading
Loading