Skip to content

feat: add dependency filtering capabilities#328

Open
stefanhoth wants to merge 3 commits intojdanil:masterfrom
stefanhoth:feat/filter-deps
Open

feat: add dependency filtering capabilities#328
stefanhoth wants to merge 3 commits intojdanil:masterfrom
stefanhoth:feat/filter-deps

Conversation

@stefanhoth
Copy link

@stefanhoth stefanhoth commented Aug 29, 2025

New Feature: Dependency Filtering

Adds dependency filtering capability to the libyear tool with a focused, CLI-only approach.

🤔 Motivation

I like the tool a lot. What was missing for internal metrics was a way to do calculations for specific package scopes. While I could have used a combination of overrides and manual calculation of the JSON output, I concluded adding top-level filtering maintains the full strength of the tooling.
Now I can use the normal command and it directly outputs a summary of all of our internal libraries.

✨ Features

  • CLI Option: --include-only for regex-based filtering
  • Regex Patterns: Support for complex include patterns
  • Multiple Patterns: Support for multiple --include-only flags
  • Comprehensive Testing: Full test coverage for filtering functionality

�� Implementation

  • New filterDependencies utility function
  • Updated CLI argument parsing
  • Updated TypeScript types and interfaces
  • Simplified approach focused on inclusion-only filtering

📚 Documentation

  • New "Filtering" section in README
  • Usage examples with npx libyear
  • Updated CLI help text

🧪 Testing

  • Unit tests for all filtering scenarios
  • Edge case handling (invalid regex, empty patterns)
  • Performance considerations

�� Files Changed

  • src/filter.ts - New filtering utility
  • src/filter.test.ts - Comprehensive test suite
  • src/types.ts - Updated types for filtering
  • src/cli/args.ts - CLI argument parsing
  • src/cli/configuration.ts - Configuration handling
  • src/cli/index.ts - CLI integration
  • src/libyear.ts - Core filtering integration
  • README.md - Documentation and examples

🔍 Usage Examples

# Include only TypeScript-related packages
npx libyear --include-only "^@types/"

# Include multiple patterns
npx libyear --include-only "^@types/" --include-only "eslint"

# Include packages from a specific scope
npx libyear --include-only "^@myorg/"

🎯 Design Decision

This implementation focuses on inclusion-only filtering to avoid the risk of users indefinitely excluding dependencies from enforcement, while still addressing the use case of checking specific package scopes. The --include-only naming makes it clear this is the only filtering option available.

- Add --include and --exclude CLI options for regex-based filtering
- Implement filterDependencies function with include/exclude logic
- Support filtering via configuration files (.libyearrc.json, etc.)
- Add comprehensive unit tests for filtering functionality
- Update README with filtering documentation and examples
- Note: package.json configuration not working with cosmiconfig v9.0.0
@stefanhoth stefanhoth marked this pull request as ready for review August 29, 2025 21:38
@stefanhoth stefanhoth requested a review from jdanil as a code owner August 29, 2025 21:38
@jdanil
Copy link
Owner

jdanil commented Sep 7, 2025

Thanks for the contribution! I appreciate the thorough testing, doc updates, --help output updates, and support via both CLI options and the config file.

I have been hesitant to support filtering (see Can I whitelist (or allowlist) dependencies from throwing errors? because I've worried that users might start filtering out dependencies they're blocked from updating, dependencies that become unmaintained, etc. which would eventually diminish the benefit of the check.

But I can see the value in using it to get metrics on a particular subset of dependencies (such as internal libraries in your example).

Let me give this a bit more thought over this week and I'll get back to you.

@stefanhoth
Copy link
Author

@jdanil Thanks for your feedback. I didn't do much research into the history of my idea. I understand you want uphold the "true meaning" of the project. At the same time, with changes like mine your tool could serve additional use-cases that carry the idea of "libyear as a single, meaningful number" into spaces that did not apply it before.

I'll hold my breath for your decision 😉

@jdanil
Copy link
Owner

jdanil commented Sep 21, 2025

@stefanhoth how would you feel about updating the PR to just support the --include CLI option? I hate to see some of your good work being reverted, but I think this would help avoid the situation of users indefinitely excluding dependencies from enforcement, while also addressing your use case of only checking specific package scopes.

- Remove --exclude CLI option and related logic
- Remove configuration file support for filtering
- Rename --include to --include-only for clarity
- Update filterDependencies function to only handle include patterns
- Update tests to cover simplified functionality
- Update README documentation to reflect changes
- Address maintainer feedback to avoid users indefinitely excluding dependencies
- Replace position-based assertions with content-based checks
- Use includes() to verify expected dependencies regardless of order
- Ensure tests remain stable if internal dependency ordering changes
- Improve test maintainability and robustness
Comment on lines -71 to +96
const { overrides, limit } = await getConfiguration(rest).then(
({
overrides,
limit: { drift, pulse, releases, major, minor, patch } = {},
}) => ({
overrides,
limit: {
driftCollective: validateLimit(drift?.collective),
driftIndividual: validateLimit(drift?.individual),
pulseCollective: validateLimit(pulse?.collective),
pulseIndividual: validateLimit(pulse?.individual),
releasesCollective: validateLimit(releases?.collective),
releasesIndividual: validateLimit(releases?.individual),
majorCollective: validateLimit(major?.collective),
majorIndividual: validateLimit(major?.individual),
minorCollective: validateLimit(minor?.collective),
minorIndividual: validateLimit(minor?.individual),
patchCollective: validateLimit(patch?.collective),
patchIndividual: validateLimit(patch?.individual),
},
}),
);
const { overrides, limit } = configuration;
const processedLimit = {
driftCollective: validateLimit(limit?.drift?.collective),
driftIndividual: validateLimit(limit?.drift?.individual),
pulseCollective: validateLimit(limit?.pulse?.collective),
pulseIndividual: validateLimit(limit?.pulse?.individual),
releasesCollective: validateLimit(limit?.releases?.collective),
releasesIndividual: validateLimit(limit?.releases?.individual),
majorCollective: validateLimit(limit?.major?.collective),
majorIndividual: validateLimit(limit?.major?.individual),
minorCollective: validateLimit(limit?.minor?.collective),
minorIndividual: validateLimit(limit?.minor?.individual),
patchCollective: validateLimit(limit?.patch?.collective),
patchIndividual: validateLimit(limit?.patch?.individual),
};
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why This Change Was Made:

  • Better Code Organization: Configuration loading is now separate from processing
  • Improved Readability: The complex destructuring and processing is now in separate steps
  • Easier Maintenance: Each step is clear and can be modified independently
  • Consistent with Filtering: The includeOnly parameter needed to be passed to libyear(), so configuration loading was moved up to make it available

@stefanhoth
Copy link
Author

@stefanhoth how would you feel about updating the PR to just support the --include CLI option? I hate to see some of your good work being reverted, but I think this would help avoid the situation of users indefinitely excluding dependencies from enforcement, while also addressing your use case of only checking specific package scopes.

@jdanil No worries, I think that's a fair compromise. Please have a look and let me know if this works for you. Thank you for the consideration!

@stefanhoth
Copy link
Author

@jdanil Ping, just in case you missed the update above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants