microsoft / microsoft/FluidFramework
Duplicate Code: package filtering logic duplicated across build-cli and build-infrastructure
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 4.9k
- Forks
- 586
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 146
Description
Analysis of commit 928277dfed7029d7ddc344e2c6389582ba762a2b
Assignee: @copilot
Summary
The package filtering logic is duplicated (near-exact copy/paste) between build-cli and build-infrastructure. The functions are identical (or trivially identical) and exceed the duplication threshold, increasing the risk of divergent behavior when one copy is updated without the other.
Duplication Details
Pattern: filterPackages (+ helper scopesToPrefix) duplicated across packages
-
Severity: Medium
-
Occurrences: 2 (exact duplicates)
-
Locations:
build-tools/packages/build-cli/src/filter.ts(lines 248–285, helper at 336–338)build-tools/packages/build-infrastructure/src/filter.ts(lines 297–334, helper at 287–289)
-
Code Sample (from
build-tools/packages/build-cli/src/filter.ts):export async function filterPackages(T extends FilterablePackage)( packages: T[], filters: PackageFilterOptions, ): Promise(T[]) { const filtered = packages.filter((pkg) => { if (filters === undefined) { return true; } const isPrivate: boolean = pkg.private ?? false; if (filters.private !== undefined && filters.private !== isPrivate) { return false; } const scopeIn = scopesToPrefix(filters?.scope); const scopeOut = scopesToPrefix(filters?.skipScope); if (scopeIn !== undefined) { let found = false; for (const scope of scopeIn) { found ||= pkg.name.startsWith(scope); } if (!found) { return false; } } if (scopeOut !== undefined) { for (const scope of scopeOut) { if (pkg.name.startsWith(scope) === true) { return false; } } } return true; }); return filtered; } function scopesToPrefix(scopes: string[] | undefined): string[] | undefined { return scopes === undefined ? undefined : scopes.map((s) => `\$\{s}/`); }
Impact Analysis
- Maintainability: Any future change (e.g., adding new filter criteria, changing scope semantics) must be replicated and kept in sync across both packages.
- Bug Risk: High chance of inconsistent fixes when only one copy is updated.
- Code Bloat: Two copies of non-trivial filtering logic.
Refactoring Recommendations
-
Extract shared filtering utility
- Extract
filterPackages+scopesToPrefixinto a shared module (suggestion):build-tools/packages/build-tools/src/common/packageFilters.ts(or similar)
- Update both
build-cliandbuild-infrastructureto import the shared implementation. - Estimated effort: Low–Medium (1–3 hours, mostly wiring/exports).
- Extract
-
Define a single source of truth and re-export
- If the dependency direction allows, keep implementation in one package and re-export from the other.
- This is less ideal than a true shared utility but still removes duplication.
Implementation Checklist
- Confirm both copies are intended to have identical semantics
- Choose a shared home package/module for the implementation
- Move code and update imports
- Run existing package/unit tests for both affected packages
- Ensure no API surface regressions
Analysis Metadata
- Detection Method: Serena semantic symbol comparison (
find_symbolonfilterPackagesandscopesToPrefix) - Analyzed Files (focused set): build-cli + build-infrastructure filter modules
- Commit:
928277dfed7029d7ddc344e2c6389582ba762a2b - Analysis Date: 2026-03-20
Generated by Duplicate Code Detector · ◷
To install this agentic workflow, run
gh aw add github/gh-aw/.github/workflows/duplicate-code-detector.md@94662b1dee8ce96c876ba9f33b3ab8be32de82a4
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by comparing filterPackages and scopesToPrefix in build-tools/packages/build-cli/src/filter.ts and build-tools/packages/build-infrastructure/src/filter.ts, then inspect the suggested shared package location and dependency direction. Choose a shared home, update both packages to use it, and run the existing package/unit tests for both affected packages to verify behavior and API compatibility.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- build-system, tooling
- Issue type
- Refactor
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100