Skip to content

[refactor] stringutil: consolidate duplicated inline ASCII-alphanumeric rune checks #47446

Description

@github-actions

Semantic Function Clustering Analysis

Analysis of repository: github/gh-aw — scoped to pkg/stats and pkg/stringutil (non-test Go files).

Executive Summary

The analyzed slice is small and, on the whole, well organized. Files in pkg/stringutil are already partitioned by feature (ansi.go, fuzzy_match.go, identifiers.go, pat_validation.go, sanitize.go, urls.go) and pkg/stats/statvar.go is a single cohesive type. One genuine low-risk duplicate was found, plus two minor organizational observations. No large-scale refactor is warranted.

  • Files analyzed: 8 (7 in stringutil, 1 in stats)
  • Functions/methods cataloged: ~35
  • Verified duplicates: 1 (inline ASCII-alphanumeric rune check)
  • Outliers (wrong file): 0 clear cases; 2 mild grouping suggestions
  • Detection method: symbol inventory + naming-cluster analysis + pattern grep

1. Duplicate: inline ASCII-alphanumeric rune check (Priority 1 — low effort)

Two functions in sanitize.go open-code the identical ASCII alphanumeric test:

  • pkg/stringutil/sanitize.go:220 — inside SanitizeIdentifierName
  • pkg/stringutil/sanitize.go:326 — inside SanitizeForFilename
// line 220 (SanitizeIdentifierName)
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '_' {

// line 326 (SanitizeForFilename)
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '-' || r == '_' || r == '.' {

Recommendation: extract a small unexported helper in sanitize.go and reuse it in both call sites:

func isASCIIAlphanumeric(r rune) bool {
	return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9')
}

Then the checks become isASCIIAlphanumeric(r) || r == '_' and isASCIIAlphanumeric(r) || r == '-' || r == '_' || r == '.'. Purely mechanical, behavior-preserving; existing tests cover both functions.

Impact: single source of truth for the character-class definition; easier to keep the two sanitizers consistent.


2. Minor: whitespace helpers could cluster (Priority 3 — optional)

stringutil.go is the catch-all file and currently mixes several unrelated concerns:

  • NormalizeWhitespace (stringutil.go:34) and NormalizeLeadingWhitespace (stringutil.go:97) — whitespace normalization
  • Truncate (stringutil.go:20), FormatList (stringutil.go:77) — formatting
  • ParseVersionValue (stringutil.go:54) — type-to-string conversion
  • IsPositiveInteger (stringutil.go:150) — validation

The two Normalize*Whitespace functions form a natural pair and could move to a whitespace.go file if this catch-all grows. Not urgent — at the current size a single utility file is idiomatic. Flagging only so it is on the radar as the file expands.


3. Confirmed good organization (no action)

  • PAT cluster (pat_validation.go): ClassifyPAT, ValidateCopilotPAT, GetPATTypeDescription + PATType methods — cohesive, correctly isolated.
  • ANSI cluster (ansi.go): StripANSI + skip*/is*CSIChar helpers — cohesive.
  • Identifier/path cluster (identifiers.go): NormalizeWorkflowName, MarkdownToLockFile, LockFileToMarkdown, NormalizeSafeOutputIdentifier — cohesive.
  • Sanitize cluster (sanitize.go): SanitizeParameterName/SanitizePythonVariableName already delegate to a shared SanitizeIdentifierName — good existing reuse.
  • stats (statvar.go): single StatVar type with focused methods — no issues.

Implementation Checklist

  • Add isASCIIAlphanumeric helper in sanitize.go and update lines 220 and 326
  • Run pkg/stringutil tests to confirm no behavior change
  • (Optional) Revisit whitespace-helper grouping if stringutil.go grows

Analysis Metadata

  • Scope: pkg/stats, pkg/stringutil (precomputed slice)
  • Duplicates detected: 1
  • Outliers: 0 clear
  • Analysis date: 2026-07-23

Generated by 🔧 Semantic Function Refactoring · sonnet46 113.5 AIC · ⌖ 10 AIC · ⊞ 9.5K ·

  • expires on Jul 24, 2026, 7:31 PM UTC-08:00

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions