Skip to content

Latest commit

 

History

History
89 lines (66 loc) · 6.63 KB

File metadata and controls

89 lines (66 loc) · 6.63 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What this repo is

C# port of Google's libphonenumber. Code was rewritten from the Java source mostly unchanged — when in doubt about behavior, the Java upstream is the source of truth.

The library tracks upstream metadata releases (~every two weeks) via the create_new_release_on_new_metadata_update.yml GitHub Action; see commits like "feat: automatic upgrade to vX.Y.Z" for what those changes look like.

Repository layout

  • csharp/PhoneNumbers/ — main library (NuGet libphonenumber-csharp). Multi-targets netstandard2.0;net8.0;net9.0;net10.0. <TreatWarningsAsErrors>true</TreatWarningsAsErrors> is set, so warnings break the build.
  • csharp/PhoneNumbers.Test/ — xUnit tests, ported from the Java tests. Multi-targets netframework4.8;net8.0;net9.0;net10.0.
  • csharp/PhoneNumbers.Extensions/ — separate NuGet (libphonenumber-csharp.extensions) with C#-idiomatic helpers that don't exist in the Java library.
  • csharp/PhoneNumbers.PerformanceTest/ — BenchmarkDotNet harness.
  • csharp/PhoneNumbers.MetadataBuilder/ — build-time tool that converts XML metadata + geocoding/timezone text files into per-region binary files. Source-links a small set of files from PhoneNumbers/ so it doesn't depend on (and can't cycle with) the main library at build time.
  • resources/ — XML metadata (PhoneNumberMetadata.xml, ShortNumberMetadata.xml, PhoneNumberAlternateFormats.xml, PhoneNumberMetadataForTesting.xml), plus geocoding/, carrier/, timezones/. These are copied verbatim from upstream — do not hand-edit. The library no longer reads them at runtime: the build pipeline emits binary equivalents under obj/metadata/, obj/geocoding/, obj/timezones/ which are embedded into the published assembly.
  • lib/update.sh + lib/DumpLocale.java — automation that pulls upstream resources and regenerates csharp/PhoneNumbers/LocaleData.cs.

Common commands

All dotnet commands run from the csharp/ directory unless noted.

Metadata is built from XML/text into per-region binary files at build time by csharp/PhoneNumbers.MetadataBuilder/ (see the BuildBinaryMetadata, BuildGeocodingBins, and BuildTimezoneBin MSBuild targets in PhoneNumbers.csproj). You don't need to run anything by hand — dotnet build invokes the tool. The previous geocoding.zip / testgeocoding.zip workflow is gone; the runtime reads binary files directly via IMetadataLoader / BuildPrefixMapFromBin.

Build / test:

dotnet restore csharp
dotnet build csharp --no-restore
# Full test matrix:
dotnet test csharp/PhoneNumbers.sln
# Faster: net9.0 only (matches the Linux PR check):
dotnet test csharp/PhoneNumbers.sln -p:TargetFrameworks=net9.0

Run a single test (xUnit filter syntax):

dotnet test csharp/PhoneNumbers.Test --filter "FullyQualifiedName~TestPhoneNumberUtil.TestParseNationalNumber"
dotnet test csharp/PhoneNumbers.Test --filter "FullyQualifiedName~TestPhoneNumberUtil"   # whole class

Pack the NuGet packages (mirrors AppVeyor):

dotnet pack -c Release csharp/PhoneNumbers
dotnet pack -c Release csharp/PhoneNumbers.Extensions

Benchmarks:

cd csharp/PhoneNumbers.PerformanceTest
dotnet run -c Release --framework net10.0 -- --filter "*"
dotnet run -c Release --framework net10.0 -- --filter "*PhoneNumberWorkflowBenchmark*"

Architecture notes that span files

  • Singleton + metadata loading. PhoneNumberUtil.GetInstance() is the entry point. Region/country metadata is lazily loaded via MetadataSource + IMetadataLoader (default impl: EmbeddedResourceMetadataLoader, which reads per-region binary files generated at build time by PhoneNumbers.MetadataBuilder and embedded under PhoneNumbers.metadata.<prefix>_<region-or-cc>). The XML parser (BuildMetadataFromXml.cs) is still used at build time and by the legacy PhoneNumberUtil(Stream) constructor for consumers loading custom XML, but is no longer on the default load path.
  • Generated files. LocaleData.cs (~48k lines) and CountryCodeToRegionCodeMap.cs are generated. LocaleData.cs is regenerated by javac DumpLocale.java && java DumpLocale > csharp/PhoneNumbers/LocaleData.cs (see lib/update.sh). Don't hand-edit either.
  • Partial-class TFM split. PhoneNumberUtil.cs is a partial class with framework-specific halves: PhoneNumberUtil.net.cs (modern .NET) and PhoneNumberUtil.netstandard.cs (netstandard2.0 fallbacks). When adding APIs that use newer BCL features, put the polyfill on the netstandard side.
  • Subsystems and their entry types (each ports a Java counterpart of the same name):
    • PhoneNumberUtil — parse / format / validate.
    • AsYouTypeFormatter — incremental formatting.
    • PhoneNumberMatcher / PhoneNumberMatch — find numbers in free text.
    • ShortNumberInfo — short codes / SMS shortcodes (separate metadata file).
    • PhoneNumberOfflineGeocoder, PhoneNumberToTimeZonesMapper — geo/tz lookups; backed by geocoding.zip / timezones/map_data.txt.
    • AreaCodeMap + AreaCodeMapStorageStrategy / DefaultMapStorage / FlyweightMapStorage — prefix → string lookup used by geocoder/carrier/timezone mappers.
  • Regex caching. Use RegexCache / PhoneRegex rather than constructing Regex ad hoc on hot paths — phone parsing is regex-heavy and the cache matters for throughput.
  • Nullable reference types are enabled only for net8.0/net9.0 targets, not netstandard2.0 (see csproj Condition). New code should still annotate.

Working with this port vs. upstream Java

  • When fixing parsing/validation bugs, first check the upstream Java equivalent (java/ in google/libphonenumber) — fixes that already exist upstream should be ported faithfully rather than reinvented. File and method names match closely (PhoneNumberUtil.javaPhoneNumberUtil.cs, BuildMetadataFromXml.javaBuildMetadataFromXml.cs, etc.).
  • Don't change resources/*.xml to fix metadata bugs. Those changes belong upstream; here they will be overwritten on the next automated metadata sync.
  • The XML-vs-protobuf and CharSequence divergences are documented in csharp/README.md ("Known Issues") — be aware they exist if you see API shape differences from Java.

CI and release

  • PRs trigger build_and_run_unit_tests_linux.yml (Ubuntu, .NET 9, net9.0 target only). AppVeyor (appveyor.yml) runs the full multi-TFM matrix on Windows and is the gate for NuGet publishes.
  • Releases are tag-driven on AppVeyor; metadata-bump releases are created automatically by create_new_release_on_new_metadata_update.yml.