-
-
Notifications
You must be signed in to change notification settings - Fork 10k
Duplicate Code: URL Param Parsing Pattern Duplicated Across Tags and Statuses Modules #34426
Copy link
Copy link
Open
Labels
cleanupMinor cleanup style change that won't show up in release changelogMinor cleanup style change that won't show up in release changelogtech debt
Description
Analysis of commit 199f656
Assignee: @copilot
Summary
The parseTagsParam and parseStatusesParam functions in the manager-api modules follow an almost identical structural pattern for parsing URL parameters with ; separators and ! negation prefixes, yet are implemented separately in two different files. Both functions are approximately 25–30 lines long, yielding over 50 lines of near-duplicate parsing logic.
Duplication Details
Pattern: URL Filter Parameter Parsing (parseTagsParam / parseStatusesParam)
- Severity: Medium
- Occurrences: 2 instances (one per file)
- Locations:
code/core/src/manager-api/modules/tags.ts(lines 18–46)code/core/src/manager-api/modules/statuses.ts(lines 9–40)
- Code Sample:
// tags.ts
export const parseTagsParam = (
tagsParam: string | undefined
): { included: Tag[]; excluded: Tag[] } => {
if (!tagsParam) {
return { included: [], excluded: [] };
}
const included: Tag[] = [];
const excluded: Tag[] = [];
tagsParam.split(';').forEach((rawTag) => {
if (!rawTag) return;
const isExcluded = rawTag.startsWith('!');
const normalizedTag = isExcluded ? rawTag.slice(1) : rawTag;
const mappedTag = (BUILT_IN_URL_TAG_MAP[normalizedTag] ?? normalizedTag) as Tag;
if (isExcluded) excluded.push(mappedTag);
else included.push(mappedTag);
});
return { included, excluded };
};
// statuses.ts — structurally identical, only the value transformation differs
export const parseStatusesParam = (
statusesParam: string | undefined
): { included: StatusValue[]; excluded: StatusValue[] } => {
if (!statusesParam) {
return { included: [], excluded: [] };
}
const included: StatusValue[] = [];
const excluded: StatusValue[] = [];
statusesParam.split(';').forEach((rawStatus) => {
if (!rawStatus) return;
const isExcluded = rawStatus.startsWith('!');
const shortName = isExcluded ? rawStatus.slice(1) : rawStatus;
const statusValue = toStatusValue(shortName);
if (!statusValue) return; // only difference: silently ignore unknown values
if (isExcluded) excluded.push(statusValue);
else included.push(statusValue);
});
return { included, excluded };
};The algorithm is identical: split by ;, strip ! prefix for excluded items, transform the raw string to a typed value, and push into included/excluded arrays.
Impact Analysis
- Maintainability: Any change to the URL parameter format (e.g. separator character, escaping rules) must be applied in two places, with a high risk of divergence.
- Bug Risk: The two implementations could silently diverge over time — for example,
parseTagsParamdoes not silently ignore unmapped values, whileparseStatusesParamdoes. This inconsistency may cause subtle URL parameter handling bugs. - Code Bloat: ~50 lines of near-identical logic that could be reduced to ~20 lines with a shared generic utility.
Refactoring Recommendations
-
Extract a generic
parseFilterParamutility- Create:
code/core/src/manager-api/lib/parseFilterParam.ts(or add to existinglib/utilities) - Signature:
parseFilterParam(T)(param: string | undefined, transform: (raw: string) => T | undefined): { included: T[]; excluded: T[] } - The
transformcallback handles value mapping (for tags:BUILT_IN_URL_TAG_MAPlookup; for statuses:toStatusValue()call) - Estimated effort: ~30 minutes
- Benefits: Single place to fix URL param parsing bugs, consistent behavior, reduced code size
- Create:
-
Update callers
parseTagsParambecomes:parseFilterParam(tagsParam, (raw) => (BUILT_IN_URL_TAG_MAP[raw] ?? raw) as Tag)parseStatusesParambecomes:parseFilterParam(statusesParam, toStatusValue)- Both callers retain their typed return signatures via generic inference
Implementation Checklist
- Review duplication findings
- Create
parseFilterParamgeneric utility - Refactor
parseTagsParamto use the utility - Refactor
parseStatusesParamto use the utility - Verify no functionality broken (existing tests for both functions)
- Update tests if needed
Analysis Metadata
- Analyzed Files: 20 changed
.ts/.tsxnon-test files from PR Sidebar: Add status-based filtering with refactored status architecture #34339 - Detection Method: Serena semantic code analysis + manual structural comparison
- Commit: 199f656
- Analysis Date: 2026-04-01
Generated by Duplicate Code Detector · ◷
To install this agentic workflow, run
gh aw add github/gh-aw/.github/workflows/duplicate-code-detector.md@852cb06ad52958b402ed982b69957ffc57ca0619
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
cleanupMinor cleanup style change that won't show up in release changelogMinor cleanup style change that won't show up in release changelogtech debt