Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
"commands": [
"sharpfuzz"
]
},
"docfx": {
"version": "2.78.5",
"commands": [
"docfx"
]
}
}
}
16 changes: 14 additions & 2 deletions .github/workflows/deploy-demo.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Deploy Demo to GitHub Pages
name: Deploy Demo & Docs to GitHub Pages

on:
push:
Expand All @@ -7,10 +7,12 @@ on:
- 'csharp/PhoneNumbers.Demo/**'
- 'csharp/PhoneNumbers/**'
- 'csharp/PhoneNumbers.Extensions/**'
# Shared build settings and package versions apply to the demo projects too.
# Shared build settings and package versions apply to the demo and docs builds too.
- 'csharp/Directory.Build.props'
- 'csharp/Directory.Packages.props'
- 'resources/**'
- 'docs/**'
- 'docfx/**'
- '.github/workflows/deploy-demo.yml'
schedule:
# Rebuild weekly to pick up any NuGet dependency updates
Expand Down Expand Up @@ -46,10 +48,20 @@ jobs:
REPO_NAME=$(echo "${{ github.repository }}" | cut -d'/' -f2)
dotnet publish csharp/PhoneNumbers.Demo/PhoneNumbers.Demo.csproj -c Release -o release -p:PathBase=/${REPO_NAME}/

# Deliberately not continue-on-error. A Pages deployment replaces the whole site, so
# carrying on past a docs failure would publish a wwwroot with no docs/ in it at all -
# taking /docs down (404, served by the SPA's 404.html) rather than leaving it stale,
# while README.md and the demo sidebar both link there. Failing the job instead means
# no deployment happens and the previous one keeps serving, demo and docs together.
# build.sh restores and builds what docfx needs, exactly as docs_preview.yml does.
- name: Build API docs site
run: ./docfx/build.sh

- name: Configure for GitHub Pages
run: |
cp release/wwwroot/index.html release/wwwroot/404.html
touch release/wwwroot/.nojekyll
cp -r docfx/_site release/wwwroot/docs

- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0

Expand Down
53 changes: 53 additions & 0 deletions .github/workflows/docs_preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: docs_preview

on:
pull_request:
branches: [ "main" ]
paths:
- 'csharp/PhoneNumbers/**'
- 'csharp/PhoneNumbers.Extensions/**'
- 'csharp/Directory.Build.props'
- 'csharp/Directory.Packages.props'
- 'docs/**'
- 'docfx/**'
- '.github/workflows/docs_preview.yml'
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

permissions:
contents: read

jobs:
build_docs_preview:
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
dotnet-version: 10.x

# build.sh restores and builds the two documented projects itself, so this runs the
# same command deploy-demo.yml does and the preview cannot pass on a build state the
# deploy will not have.
- name: Build API docs site
run: ./docfx/build.sh

# No GitHub Pages deploy here (that only happens from main, in deploy_demo.yml) — this
# is purely so a PR reviewer can view the rendered site without merging. Download the
# "api-docs-preview" artifact from this run's summary, unzip it, and serve it with any
# static file server (e.g. `python3 -m http.server` from inside the unzipped folder) —
# opening index.html directly via file:// won't work, the site fetches its nav/search
# data with relative requests that require a real HTTP origin.
- name: Upload docs preview artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: api-docs-preview
path: docfx/_site
retention-days: 14
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,11 @@ coverage/
/fuzz-out/
/corpus-cache/
/artifacts/

# DocFX build output: api/ is metadata extracted from XML doc comments, _site/ is the
# generated static site, and articles/*.md is copied in from docs/ (see docfx/build.sh).
# All regenerated by docfx/build.sh.
/docfx/api/
/docfx/_site/
/docfx/obj/
/docfx/articles/*.md
13 changes: 12 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ automatically every ~two weeks; the library compiles it to binaries at build tim
- `lib/` — bash automation for the metadata sync, changelog and release. The sync runs daily and
opens a `metadata-update/*` PR with auto-merge off for a maintainer to review and merge; a later
run that finds it still open regenerates the branch and arms auto-merge as a backstop.
- `docfx/` — DocFX config for the generated API reference site, deployed alongside the demo under
`/docs/` in the same `deploy-demo.yml` run. Build it with `docfx/build.sh`, never `docfx`
directly — the script copies `docs/*.md` in as articles and rewrites their repo-relative links.
`docfx/template/public/main.css` ports the demo's design tokens onto DocFX's `modern` template
so the two sites match; `docs_preview.yml` uploads the rendered site as a PR artifact.
- `docfx/brand/` — the docs site's logomark and favicon SVGs, mapped to `images/` by
`docfx/docfx.json`. Only docfx reads them; the demo draws its rail logo from a Razor component
under `csharp/PhoneNumbers.Demo/Components/Icons/`.
- `docs/api-differences-from-java.md` — the deliberate API-shape divergences from Java.

## Common commands
Expand All @@ -52,7 +60,10 @@ dotnet test csharp/PhoneNumbers.Test --filter "FullyQualifiedName~TestPhoneNumbe
## Hard rules

- **Don't hand-edit `resources/`** (overwritten by the next sync — metadata fixes go upstream), or
the generated `CountryCodeToRegionCodeMap.cs` and `resources/locale/country_names.txt`.
the generated `resources/locale/country_names.txt`. `CountryCodeToRegionCodeMap.cs` reads like a
generated file and is named like one, but nothing regenerates it — its own header still says
"todo make this file automatically generated", and `lib/github-actions-metadata-update.sh`
deliberately treats a change to it as hand-written content. Edit it by hand when you need to.
- **Adding a public member to `csharp/PhoneNumbers/` needs explicit sign-off from the user, as its
own decision.** Package validation only catches breaks against the published baseline — never
additions, so nothing automated will object. "It matches an existing pattern" is not permission —
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@

C# port of Google's [libphonenumber library](https://github.com/google/libphonenumber).

The code was rewritten from the Java source mostly unchanged, please refer to the original documentation for sample code and API documentation.
The code was rewritten from the Java source mostly unchanged, please refer to the original documentation for sample code, and see the [API reference](https://twcclegg.github.io/libphonenumber-csharp/docs/) for this port's own types and members.

The original Apache License 2.0 was preserved.

> [!TIP]
> **[Try the interactive demo →](https://twcclegg.github.io/libphonenumber-csharp/)** — parse, format, validate, and find phone numbers in your browser. No install required; runs entirely via WebAssembly.
>
> **[Browse the API reference →](https://twcclegg.github.io/libphonenumber-csharp/docs/)** — generated from this library's XML doc comments.

See [this](csharp/README.md) for details about the port.

Expand Down
2 changes: 2 additions & 0 deletions csharp/PhoneNumbers.Demo/Components/Icons/BookIcon.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@inherits IconBase
<Icon @attributes="AdditionalAttributes"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></Icon>
12 changes: 12 additions & 0 deletions csharp/PhoneNumbers.Demo/Layout/MainLayout.razor
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@

<div class="sidebar__section">
<div class="sidebar__section-title">Resources</div>
<a href="@DocsUrl" class="sidebar__link">
<span class="sidebar__link-icon" aria-hidden="true">
<BookIcon />
</span>
API Docs
</a>
<a href="https://github.com/twcclegg/libphonenumber-csharp" target="_blank" rel="noopener" class="sidebar__link">
<span class="sidebar__link-icon" aria-hidden="true">
<GitHubIcon />
Expand Down Expand Up @@ -152,6 +158,12 @@
private bool _shareCopied;
private string _currentTitle = "Home";

// The API docs site is published as a sibling folder alongside this app (see
// deploy-demo.yml, which copies docfx's output to release/wwwroot/docs). Nav.BaseUri
// already includes the GitHub Pages repo-name PathBase, so this resolves correctly
// regardless of which client-side route the user is currently on.
private string DocsUrl => $"{Nav.BaseUri}docs/";

private static readonly Dictionary<string, string> Titles = new()
{
[""] = "Home",
Expand Down
6 changes: 6 additions & 0 deletions csharp/PhoneNumbers/AreaCodeMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/

using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;

namespace PhoneNumbers
Expand All @@ -25,6 +26,11 @@ namespace PhoneNumbers
/// covers.
/// </summary>
/// <remarks>Author: Shaopeng Jia</remarks>
// Implementation detail: prefix -> description lookup behind the geocoder, carrier and
// timezone mappers. Public only because the port mirrored Java's class layout, not
// because callers are meant to reach it; hidden from IntelliSense and from the
// generated API reference.
[EditorBrowsable(EditorBrowsableState.Never)]
public class AreaCodeMap
{
private readonly PhoneNumberUtil phoneUtil = PhoneNumberUtil.GetInstance();
Expand Down
5 changes: 5 additions & 0 deletions csharp/PhoneNumbers/AreaCodeMapStorageStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace PhoneNumbers
Expand All @@ -25,6 +26,10 @@ namespace PhoneNumbers
/// provided data.
/// <!-- @author Philippe Liard -->
/// </summary>
// Implementation detail: storage strategy for AreaCodeMap. Public only because the port
// mirrored Java's class layout, not because callers are meant to reach it; hidden from
// IntelliSense and from the generated API reference.
[EditorBrowsable(EditorBrowsableState.Never)]
public abstract class AreaCodeMapStorageStrategy
{
protected int NumOfEntries;
Expand Down
5 changes: 5 additions & 0 deletions csharp/PhoneNumbers/BuildMetadataFromBin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/

using System;
using System.ComponentModel;
using System.IO;
using System.Text;

Expand All @@ -32,6 +33,10 @@ namespace PhoneNumbers
/// Java's framing buys us nothing here and complicates the writer. The format is versioned so
/// it can evolve without breaking older consumers if a binary is shipped without rebuilding.
/// </remarks>
// Implementation detail: reads the binary metadata the build pipeline emits. Public
// only because the port mirrored Java's class layout, not because callers are meant to
// reach it; hidden from IntelliSense and from the generated API reference.
[EditorBrowsable(EditorBrowsableState.Never)]
public static class BuildMetadataFromBin
{
// 4-byte magic + 1-byte version. Bumped if the schema below changes incompatibly.
Expand Down
6 changes: 6 additions & 0 deletions csharp/PhoneNumbers/BuildMetadataFromXml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
Expand All @@ -28,6 +29,11 @@

namespace PhoneNumbers
{
// Implementation detail: XML metadata parser. Consumers with their own metadata go
// through PhoneNumberUtil.CreateInstance(Stream), which drives this internally. Public
// only because the port mirrored Java's class layout, not because callers are meant to
// reach it; hidden from IntelliSense and from the generated API reference.
[EditorBrowsable(EditorBrowsableState.Never)]
public class BuildMetadataFromXml
{
// String constants used to fetch the XML nodes and attributes.
Expand Down
5 changes: 5 additions & 0 deletions csharp/PhoneNumbers/BuildPrefixMapFromBin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Text;

Expand All @@ -27,6 +28,10 @@ namespace PhoneNumbers
/// for timezone maps (long prefix, string[] descriptions). Each gets its own magic so the
/// reader can fail loudly if a caller passes the wrong stream.
/// </remarks>
// Implementation detail: reads the binary prefix maps the build pipeline emits. Public
// only because the port mirrored Java's class layout, not because callers are meant to
// reach it; hidden from IntelliSense and from the generated API reference.
[EditorBrowsable(EditorBrowsableState.Never)]
public static class BuildPrefixMapFromBin
{
// Magic + version layout matches BuildMetadataFromBin so future tooling can sniff a stream.
Expand Down
5 changes: 5 additions & 0 deletions csharp/PhoneNumbers/CountryCodeToRegionCodeMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@
*/

using System.Collections.Generic;
using System.ComponentModel;

namespace PhoneNumbers
{
// Implementation detail: the country-code -> region-code lookup table the library reads
// at startup. Public only because the port mirrored Java's class layout, not because
// callers are meant to reach it; hidden from IntelliSense and from the API reference.
[EditorBrowsable(EditorBrowsableState.Never)]
public static class CountryCodeToRegionCodeMap
{
// A mapping from a country code to the region codes which denote the
Expand Down
5 changes: 5 additions & 0 deletions csharp/PhoneNumbers/DefaultMapStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace PhoneNumbers
Expand All @@ -27,6 +28,10 @@ namespace PhoneNumbers
/// is actually unnecessary (i.e no string duplication).
/// </summary>
/// <remarks>Author: Shaopeng Jia</remarks>
// Implementation detail: AreaCodeMap storage strategy. Public only because the port
// mirrored Java's class layout, not because callers are meant to reach it; hidden from
// IntelliSense and from the generated API reference.
[EditorBrowsable(EditorBrowsableState.Never)]
public class DefaultMapStorage : AreaCodeMapStorageStrategy
{
private int[] phoneNumberPrefixes;
Expand Down
5 changes: 5 additions & 0 deletions csharp/PhoneNumbers/FlyweightMapStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace PhoneNumbers
Expand All @@ -28,6 +29,10 @@ namespace PhoneNumbers
/// the provided area code map contains a lot of description redundant descriptions.
/// </summary>
/// <remarks>Author: Philippe Liard</remarks>
// Implementation detail: AreaCodeMap storage strategy. Public only because the port
// mirrored Java's class layout, not because callers are meant to reach it; hidden from
// IntelliSense and from the generated API reference.
[EditorBrowsable(EditorBrowsableState.Never)]
public class FlyweightMapStorage : AreaCodeMapStorageStrategy
{
// Size of short and integer types in bytes.
Expand Down
5 changes: 5 additions & 0 deletions csharp/PhoneNumbers/MappingFileProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

Expand All @@ -28,6 +29,10 @@ namespace PhoneNumbers
/// calling code and language that the text descriptions are in.
/// </summary>
/// <remarks>Author: Shaopeng Jia</remarks>
// Implementation detail: picks the geocoding/carrier data file for a locale. Public
// only because the port mirrored Java's class layout, not because callers are meant to
// reach it; hidden from IntelliSense and from the generated API reference.
[EditorBrowsable(EditorBrowsableState.Never)]
public class MappingFileProvider
{
private static readonly Dictionary<string, string> LocaleNormalizationMap;
Expand Down
7 changes: 6 additions & 1 deletion csharp/PhoneNumbers/MetadataFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
*/

using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace PhoneNumbers
{
Expand All @@ -29,6 +30,10 @@ namespace PhoneNumbers
/// changes without notice. Any changes are not guaranteed to be reflected in the versioning scheme
/// of the public API, nor in release notes.
/// </summary>
// Implementation detail: strips unused metadata fields at build time. Public only
// because the port mirrored Java's class layout, not because callers are meant to reach
// it; hidden from IntelliSense and from the generated API reference.
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class MetadataFilter
{
// The following 3 sets comprise all the PhoneMetadata fields as defined at phonemetadata.proto
Expand Down
4 changes: 4 additions & 0 deletions csharp/PhoneNumbers/MetadataManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ namespace PhoneNumbers
/// XML files. <para/>
/// Author: Lara Rennie
/// </remarks>
// Implementation detail: metadata loading plumbing. Public only because the port
// mirrored Java's class layout, not because callers are meant to reach it; hidden from
// IntelliSense and from the generated API reference.
[EditorBrowsable(EditorBrowsableState.Never)]
public static class MetadataManager
{
private const string AlternateFormatsPrefix = "PhoneNumberAlternateFormats";
Expand Down
Loading
Loading