marmelroy/PhoneNumberKit
A Swift framework for parsing, formatting and validating international phone numbers. Inspired by Google's libphonenumber.
Healthy across all four use cases
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 1d ago
- ✓14 active contributors
- ✓MIT licensed
Show 3 more →Show less
- ✓CI configured
- ⚠Concentrated ownership — top contributor handles 61% of recent commits
- ⚠No test directory detected
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/marmelroy/phonenumberkit)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/marmelroy/phonenumberkit on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: marmelroy/PhoneNumberKit
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/marmelroy/PhoneNumberKit shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- Last commit 1d ago
- 14 active contributors
- MIT licensed
- CI configured
- ⚠ Concentrated ownership — top contributor handles 61% of recent commits
- ⚠ No test directory detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live marmelroy/PhoneNumberKit
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/marmelroy/PhoneNumberKit.
What it runs against: a local clone of marmelroy/PhoneNumberKit — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in marmelroy/PhoneNumberKit | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | Last commit ≤ 31 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of marmelroy/PhoneNumberKit. If you don't
# have one yet, run these first:
#
# git clone https://github.com/marmelroy/PhoneNumberKit.git
# cd PhoneNumberKit
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of marmelroy/PhoneNumberKit and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "marmelroy/PhoneNumberKit(\\.git)?\\b" \\
&& ok "origin remote is marmelroy/PhoneNumberKit" \\
|| miss "origin remote is not marmelroy/PhoneNumberKit (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 31 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~1d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/marmelroy/PhoneNumberKit"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
PhoneNumberKit is a Swift framework that parses, formats, and validates international phone numbers using metadata from Google's libphonenumber library. It handles phone number standardization for 200+ regions, supports real-time AsYouType formatting for text fields, and provides country code conversions—all without native C dependencies. Single-package structure: core parsing logic in PhoneNumberKit/ (ParseManager.swift, PhoneNumberParser.swift, RegexManager.swift), formatting separated into Formatter.swift and PartialFormatter.swift, metadata bundled as resources in PhoneNumberKit/Resources/ with version tracking. Public API exposed through PhoneNumberUtility.swift and PhoneNumber.swift. Tests and examples organized at project root.
👥Who it's for
iOS/macOS/watchOS/tvOS developers building apps requiring international phone number handling (e.g. auth flows, contact management, SMS integration). Developers who need Google libphonenumber accuracy but want pure Swift with lightweight footprint.
🌱Maturity & risk
Production-ready and actively maintained. The repo shows consistent CI/CD pipelines (GitHub Actions for PR tests, automated releases, metadata updates), multiple supported platforms (iOS, macOS, tvOS, watchOS via xcschemes), and comprehensive testing infrastructure. Last activity visible in workflow setup suggests ongoing maintenance.
Low risk for established apps. Single maintainer (marmelroy) is typical for Swift libraries. Metadata must be kept current—repo includes update_metadata.yml workflow suggesting this is managed. No dependency bloat (pure Swift stdlib + metadata). Breaking changes would be flagged in migration guides (OXMIGRATIONGUIDE.md exists). Main risk: relies entirely on libphonenumber metadata accuracy.
Active areas of work
Actively maintaining CI/CD workflows (pr.yml, publish-cocoapods.yml, release.yml). Automated metadata updates via update_metadata.yml workflow suggest continuous synchronization with Google's libphonenumber. Swift version and linting configs updated (swiftformat, swiftlint configurations present).
🚀Get running
git clone https://github.com/marmelroy/PhoneNumberKit.git && cd PhoneNumberKit && open PhoneNumberKit.xcodeproj (for Xcode) OR swift build (via SPM using Package.swift). CocoaPods users: pod install PhoneNumberKit.
Daily commands: xcodebuild -project PhoneNumberKit.xcodeproj -scheme PhoneNumberKit test (run test suite) OR swift test (SPM). For framework use: import PhoneNumberKit; let utility = PhoneNumberUtility(); try utility.parse("+33689017383").
🗺️Map of the codebase
- PhoneNumberKit/PhoneNumberParser.swift: Core parsing engine that applies regex patterns and metadata rules to extract phone number components
- PhoneNumberKit/MetadataParsing.swift: Parses bundled libphonenumber metadata JSON at runtime into MetadataTypes structures for validation and formatting rules
- PhoneNumberKit/PartialFormatter.swift: Implements real-time AsYouType formatting for UITextField with incremental parsing
- PhoneNumberKit/RegexManager.swift: Caches and manages compiled NSRegularExpression patterns to avoid recompilation overhead on hot paths
- PhoneNumberKit/PhoneNumberUtility.swift: Public API entry point; orchestrates metadata loading, parsing, formatting, and validation for end users
- PhoneNumberKit/Resources/: Bundles Google libphonenumber metadata JSON files (multiple GB when expanded); versioned via .metadata-version file
🛠️How to make changes
Parsing logic: PhoneNumberParser.swift and ParseManager.swift. Formatting: Formatter.swift (standard) and PartialFormatter.swift (AsYouType). Validation rules: consult MetadataTypes.swift and MetadataParsing.swift for region metadata structure. Adding new formats: extend PhoneNumberFormatter.swift. Tests are colocated in Xcode project; use .xcodeproj schemes for running subsets.
🪤Traps & gotchas
Metadata must be kept synchronized with Google's libphonenumber—out-of-sync data causes validation failures for new country codes. PhoneNumberUtility is expensive to initialize (parses all metadata into memory); create once per app lifecycle, not per-call. Regex compilation happens lazily; first parse call may show latency spikes. Bundle resources must be included in app target copy phase or parsing will fail silently. No network calls—all validation is offline via bundled data.
💡Concepts to learn
- Metadata-Driven Validation — PhoneNumberKit loads region-specific validation rules (digit lengths, format patterns) from bundled libphonenumber metadata at runtime, rather than hardcoding—this allows supporting 200+ countries without code changes
- Lazy Regex Compilation & Caching — RegexManager.swift caches compiled NSRegularExpression objects to avoid recompiling regex patterns on every parse call; critical for performance when parsing 1000+ numbers
- AsYouType Formatting (Incremental) — PartialFormatter.swift applies region-aware formatting rules incrementally as users type into UITextField, providing real-time visual feedback without blocking interaction
- Codable Serialization — PhoneNumber+Codable.swift enables JSON encoding/decoding of parsed phone number objects; essential for API communication and local persistence
- Resource Bundling & Versioning — PhoneNumberKit bundles 100+ MB of libphonenumber metadata XML/JSON in Resources/; .metadata-version file tracks which libphonenumber release is embedded to ensure consistency
- E.164 International Format — PhoneNumberKit normalizes all numbers to E.164 format (+CC-NNNNNNNNNNN) as canonical representation, enabling consistent comparison and storage across regions
🔗Related repos
google/libphonenumber— The canonical Java/C++ reference implementation that PhoneNumberKit ports to Swift; metadata source of truthgooglei18n/libphonenumber— Official i18n-maintained fork of libphonenumber providing up-to-date metadata and validation rulesswiftlang/swift-foundation— Swift standard library; PhoneNumberKit relies on Foundation regex and Codable for core functionalityCocoaPods/Specs— Package registry where PhoneNumberKit is published; publish-cocoapods.yml automates releases to Specsapple/swift-package-manager— SPM infrastructure used for SwiftPM distribution via Package.swift; governs build reproducibility
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test coverage for PhoneNumberFormatter edge cases
PhoneNumberKitTests has PartialFormatterTests.swift but lacks dedicated PhoneNumberFormatterTests.swift. The Formatter.swift and PhoneNumberFormatter.swift classes handle critical formatting logic for international phone numbers across different formats (E164, INTERNATIONAL, NATIONAL, RFC3966). A new test suite should cover edge cases like malformed inputs, boundary conditions for different country codes, and format transitions.
- [ ] Create PhoneNumberKitTests/PhoneNumberFormatterTests.swift
- [ ] Add tests for E164, INTERNATIONAL, NATIONAL, and RFC3966 formats
- [ ] Include edge cases: empty strings, null regions, invalid country codes
- [ ] Test all format combinations from PhoneNumberFormat enum in Constants.swift
- [ ] Verify output matches libphonenumber behavior for common countries
Add unit tests for MetadataManager and MetadataParsing
MetadataManager.swift and MetadataParsing.swift are critical for loading and parsing PhoneNumberMetadata.json (18+ MB file with country/region data). The existing tests don't have dedicated coverage for metadata initialization, caching, parsing failures, and metadata version updates. This is crucial since update_metadata.sh and update_metadata.yml workflow exist but lack corresponding integration tests.
- [ ] Create PhoneNumberKitTests/MetadataManagerTests.swift
- [ ] Test metadata loading from bundle resources (PhoneNumberKit/Resources/PhoneNumberMetadata.json)
- [ ] Test caching mechanism and singleton pattern
- [ ] Add tests for metadata parsing failures and corrupt data handling
- [ ] Verify metadata version tracking matches .metadata-version file
Add iOS UI component integration tests for PhoneNumberTextField and CountryCodePickerViewController
PhoneNumberTextField.swift and CountryCodePickerViewController.swift provide critical UI components but PhoneNumberTextFieldTests.swift only has basic tests. Missing coverage for real-world scenarios like locale changes, keyboard interactions, filtering country lists, and state restoration. CountryCodePickerTableViewCell.swift and CountryCodePickerSectionHeaderView.swift lack dedicated tests.
- [ ] Expand PhoneNumberKitTests/PhoneNumberTextFieldTests.swift with delegate callback testing
- [ ] Create PhoneNumberKitTests/CountryCodePickerViewControllerTests.swift
- [ ] Test country filtering and search functionality in CountryCodePickerViewController
- [ ] Add tests for PhoneNumberTextFieldDelegate callbacks (validation, formatting during typing)
- [ ] Test UITableView data source methods for picker cells and section headers
🌿Good first issues
- Add unit test coverage for edge cases in PartialFormatter.swift (AsYouType formatter) around format transitions (e.g. '+1 (23' → '+1 (234)'), which currently lacks explicit test cases
- Document the metadata JSON schema and update CLAUDE.md with metadata version management workflow—update_metadata.yml exists but its prerequisites and validation steps aren't documented for contributors
- Extend PhoneNumberFormatter.swift with a new public method for consistent formatting across all ISO 3166 calling codes, covering missing regional variants (check GitHub issues for 'formatting' keywords)
⭐Top contributors
Click to expand
Top contributors
- @github-actions[bot] — 61 commits
- @bguidolim — 25 commits
- @michalsrutek — 3 commits
- @EugenePetlitskiy — 1 commits
- @MarcGarciaSunweb — 1 commits
📝Recent commits
Click to expand
Recent commits
2d547ff— Release 4.2.12 (github-actions[bot])b124a5c— Updated metadata to version metadata/9.0.30 (#902) (github-actions[bot])840ca3a— Release 4.2.11 (github-actions[bot])0f299e8— Updated metadata to version metadata/9.0.29 (#899) (github-actions[bot])c15542f— Release 4.2.10 (github-actions[bot])73499fd— Updated metadata to version metadata/9.0.28 (#898) (github-actions[bot])f6b6125— Release 4.2.9 (github-actions[bot])7d1489f— Updated metadata to version metadata/9.0.27 (#897) (github-actions[bot])aa16e94— perf: replace DispatchQueue.sync with NSLock in RegexManager to prevent UI freezes (#893) (EugenePetlitskiy)54f678c— Release 4.2.8 (github-actions[bot])
🔒Security observations
PhoneNumberKit demonstrates generally good security posture as a data parsing library. The main concerns are around metadata handling (XML parsing potential XXE vulnerabilities and automated updates without verification) and the lack of formal security policy. The codebase appears free of SQL injection, XSS, and hardcoded credentials risks due to its nature as a phone number parsing utility. Swift's type safety and the absence of direct infrastructure components mitigate many common vulnerabilities. Recommendations focus on establishing security processes (responsible disclosure policy), hardening metadata management (checksums, pinning), and ensuring dependency monitoring is in place.
- Medium · Metadata File in Plain XML Format —
PhoneNumberKit/Resources/Original/PhoneNumberMetadata.xml. The repository contains PhoneNumberMetadata.xml in the Resources/Original directory. While this is metadata for phone number parsing, storing both XML and JSON versions of the same data increases attack surface and maintenance burden. The XML format could be vulnerable to XXE (XML External Entity) attacks if parsed without proper safeguards. Fix: Ensure XML parsing is configured to disable external entity resolution. Remove the original XML file from distribution if only the JSON version is needed. Verify that NSXMLParser or any XML parsing library used has XXE protections enabled. - Medium · Automated Metadata Updates Without Pinning —
PhoneNumberKit/Resources/update_metadata.sh, .github/workflows/update_metadata.yml. The update_metadata.sh script and update_metadata.yml workflow suggest automated updates to phone number metadata. Without version pinning or checksum verification, this could introduce unexpected changes or supply chain attacks if the upstream source is compromised. Fix: Implement checksum verification for downloaded metadata files. Pin metadata versions explicitly. Review all automated updates before merging. Consider storing metadata updates in a separate PR for review rather than automatic commits. - Low · Missing Security.md or Security Policy —
Repository root. No SECURITY.md file found in the repository root. This makes it difficult for security researchers to report vulnerabilities responsibly. Fix: Create a SECURITY.md file following GitHub's security policy template. Include instructions for responsible disclosure and how to contact maintainers with security issues. - Low · No Dependency Vulnerability Scanning Configuration —
.github configuration. No evidence of dependency scanning tools (e.g., Dependabot configuration) in the provided file structure. The Swift Package Manager and CocoaPods dependencies are not explicitly tracked for known vulnerabilities. Fix: Enable Dependabot for Swift Package Manager dependencies. Add regular security audit workflows. Consider integrating tools like swift-outdated or dependencycheck into CI/CD pipeline. - Low · Potential Information Disclosure via Build Artifacts —
PhoneNumberKit.xcodeproj/xcshareddata/xcbaselines/. The repository contains test baseline files and Xcode workspace configurations that could expose build-time information. While low risk for this library, these artifacts could reveal system paths or build environment details. Fix: Review .gitignore to ensure build artifacts, temporary files, and developer-specific configurations are properly excluded. Consider adding.xcbaselines/to gitignore if they are regenerated during builds.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.