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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ pnpm build

# Filter by partial match (case-insensitive)
./dist/cli.js --filter API
./dist/cli.js -f API
./dist/cli.js --filter database
./dist/cli.js -f database

# Display help
./dist/cli.js --help
Expand Down
2 changes: 1 addition & 1 deletion src/cli/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function formatHelpText(): string {
'Options:',
' -h, --help display help for command',
' -v, --version display version number',
' --filter TEXT filter variables containing TEXT (case-insensitive)',
' -f, --filter TEXT filter variables containing TEXT (case-insensitive)',
'',
CLI_MESSAGES.HELP_EXAMPLES,
CLI_MESSAGES.HELP_DESCRIPTION,
Expand Down
3 changes: 2 additions & 1 deletion src/constants/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const OPTION_ALIASES: Record<string, string> = {
h: 'help',
v: 'version',
V: 'version',
f: 'filter',
};

/**
Expand All @@ -18,7 +19,7 @@ export const EXIT_CODES = {
SUCCESS: 0,
SYSTEM_ERROR: 1,
DATA_NOT_FOUND: 2,
INVALID_ARGUMENT: 2, // UNIX convention: invalid argument uses exit code 2
INVALID_ARGUMENT: 2,
} as const;

export type ExitCode = (typeof EXIT_CODES)[keyof typeof EXIT_CODES];
43 changes: 25 additions & 18 deletions src/core/filter.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,44 @@
import type { EnvironmentData, FilterConfig, FilterResult } from '../types/environment.js';
import { ERROR_MESSAGES, CLI_MESSAGES } from '../constants/index.js';

/**
* Creates a filter function that matches environment variables by type and search text
* @param type - The type of filter ('prefix' or 'partial')
* @param searchText - The text to match (case-insensitive)
* @returns A filter function that checks if a variable matches the criteria
*/
export function createFilter(
type: 'prefix' | 'partial',
searchText: string,
): (env: EnvironmentData) => boolean {
const lowerSearchText = searchText.toLowerCase();

return (env: EnvironmentData): boolean => {
const lowerKey = env.key.toLowerCase();
return type === 'prefix'
? lowerKey.startsWith(lowerSearchText)
: lowerKey.includes(lowerSearchText);
};
}

/**
* Creates a filter function that matches environment variables by prefix
* @param prefix - The prefix to match (case-insensitive)
* @returns A filter function that checks if a variable starts with the prefix
* @deprecated Use createFilter('prefix', prefix) instead
*/
export function createPrefixFilter(prefix: string): (env: EnvironmentData) => boolean {
const lowerPrefix = prefix.toLowerCase();

return (env: EnvironmentData): boolean => {
return env.key.toLowerCase().startsWith(lowerPrefix);
};
return createFilter('prefix', prefix);
}

/**
* Creates a filter function that matches environment variables by partial match
* @param searchText - The text to search for (case-insensitive)
* @returns A filter function that checks if a variable contains the search text
* @deprecated Use createFilter('partial', searchText) instead
*/
export function createPartialMatchFilter(searchText: string): (env: EnvironmentData) => boolean {
const lowerSearchText = searchText.toLowerCase();

return (env: EnvironmentData): boolean => {
return env.key.toLowerCase().includes(lowerSearchText);
};
return createFilter('partial', searchText);
}

/**
Expand All @@ -50,14 +64,7 @@ export function filterEnvironmentVariables(
}

// Apply appropriate filter based on type
let filter: (env: EnvironmentData) => boolean;

if (config.type === 'prefix') {
filter = createPrefixFilter(config.value);
} else {
// config.type === 'partial'
filter = createPartialMatchFilter(config.value);
}
const filter = createFilter(config.type, config.value);

const filtered = data.filter(filter);

Expand Down
31 changes: 31 additions & 0 deletions tests/unit/cli/parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,37 @@ describe('CLI Parser', () => {
expect(result.data.arguments).toEqual(['PREFIX']);
}
});

it('should parse -f option with value', () => {
const result = parseArgs(['node', 'cli.js', '-f', 'API'], mockConfig);

expect(result.success).toBe(true);
if (result.success) {
expect(result.data.command).toBe('main');
expect(result.data.flags.has('filter')).toBe(true);
expect(result.data.filterValue).toBe('API');
expect(result.data.arguments).toEqual([]);
}
});

it('should handle -f without value', () => {
const result = parseArgs(['node', 'cli.js', '-f'], mockConfig);

expect(result.success).toBe(false);
if (!result.success) {
expect(result.error.type).toBe('filter_requires_value');
expect(result.error.message).toBe('--filter option requires a search text');
}
});

it('should trim whitespace from -f value', () => {
const result = parseArgs(['node', 'cli.js', '-f', ' API '], mockConfig);

expect(result.success).toBe(true);
if (result.success) {
expect(result.data.filterValue).toBe('API');
}
});
});

describe('isValidOption', () => {
Expand Down