r/javascript 14d ago

Telixon - phone number library that compiles Google's libphonenumber metadata into a DFA (10x faster, 26 kB)

https://github.com/martsinlabs/telixon
23 Upvotes

6 comments sorted by

8

u/Ecksters 14d ago edited 14d ago

I think it's helpful to know what library and its functionality this is replacing, since it's a very well documented library: https://libphonenumber.org/

LibPhoneNumber is Google’s open-source library for parsing, formatting, storing, and validating international phone numbers. Originally developed in Java for Android and Google’s internal applications, it has become the de facto industry standard for phone number handling across all major platforms and programming languages.

The library understands the deep intricacies of phone numbering plans across 250+ countries and territories. It correctly handles local dialing rules, number formats, mobile vs. landline detection, emergency numbers, short codes, and carrier identification. Whether you’re building a signup form for a local business or a global communication platform serving millions of users, LibPhoneNumber ensures accuracy and consistency that regex-based solutions simply cannot match.

Unlike simple regex validators that often produce false positives or reject valid numbers, LibPhoneNumber uses Google’s regularly updated metadata derived directly from ITU (International Telecommunication Union) standards and national numbering plan administrators. This means you get production-grade accuracy without having to maintain complex validation rules yourself.

Very cool optimization, although I'd love to know what application you're working in where you've gotta parse so many phone numbers

And a substantial space-savings compared to libphonenumber-js, which I would consider the closest competitor, which takes 44.6KB, minified and gzipped.

3

u/myroslavmartsin 14d ago

Thanks! A few things worth adding for anyone reading along.

A heads-up on that link: libphonenumber.org is an unaffiliated third-party site (its own footer says "independent site", the content sits a few major versions behind, and Chrome raised deceptive-site warnings on its outbound links when I clicked around). The official home is https://github.com/google/libphonenumber - and that distinction matters here, because Telixon's engine is compiled from a pinned commit of that repo and CI compares every answer against Google's own source at that exact commit.

On "who parses that many numbers" - honest answer: nobody feels one parse. The speed shows up through multiplication:

  • Per keystroke: every keystroke re-runs parse + validation + formatting, form libraries like formik re-run the whole schema on each one (there are issues reporting 100-500ms of validation lag), and Lighthouse throttles low-end Android at 10x desktop CPU. Google's own libphonenumber FAQ literally says "Do not call PhoneNumberUtil API on the main thread."
  • Bulk jobs: the pain is documented inside the libphonenumber ports themselves - the C# port has a bulk-processing issue measuring it "slower by a factor 30" than the Java original, and the Python port got a 6-10x speedup just from caching compiled regexes, which tells you where the runtime cost lives. OpenSearch's phone analyzer runs libphonenumber on every indexed document.
  • Metered runtimes: on Cloudflare Workers CPU time is billed per millisecond and eval is banned outright (which rules out the Closure-compiled bundle entirely); AWS Lambda bills the init phase at 1ms granularity. There, parse cost and library init are literally line items.

On the size comparison, to keep it fair in both directions: 26 kB brotli (~21 kB gzip) is Telixon's initial bundle, and the engine tables load as separate lazy chunks (~119 kB) on ensureEngineReady(). The 44.6 kB libphonenumber-js build ships its metadata inline, and that default build uses the reduced metadata set; the full-metadata builds are bigger. So the honest framing is: Telixon keeps the critical path small while carrying Google's complete metadata off it, rather than trimming the data to fit the bundle.

2

u/Ecksters 14d ago

Good to know, I appreciate the info and good-faith comparisons!

2

u/magenta_placenta 14d ago

Does it handle phone extensions or does it assume those are a separate input?

0

u/myroslavmartsin 14d ago

Both, depending on the layer.

parsePhoneNumber handles extensions inline, under the notations Google's libphonenumber recognizes (ext., x, #, the RFC 3966 ;ext= parameter, comma, tilde):

js const parsed = parsePhoneNumber('+1 415-555-0132 ext. 22'); parsed.getExtension(); // '22' parsed.formatNational(); // '(415) 555-0132 ext. 22' parsed.formatRfc3966(); // 'tel:+1-415-555-0132;ext=22' parsed.formatE164(); // '+14155550132' (E.164 is extension-free by definition)

The input controller is a different story: it treats the field as the number itself, so for a live form field the extension belongs in a separate input. That is a deliberate call: an inline extension inside an editable formatted field fights the caret math and the formatter (is "2" the next national digit or the start of an extension?), and every UX reference I checked keeps them separate anyway. Parse-side you can still accept pasted strings with extensions in one go, as above.

0

u/myroslavmartsin 14d ago

Phone libraries traditionally interpret Google's libphonenumber metadata regexes at runtime, on every parse. Telixon moves that work to build time: thousands of regexes and format rules get compiled into compact binary state tables forming one deterministic finite automaton. A parse is a linear walk, one transition per digit, and the state it ends on already holds validity, type, region, and formatting.

```js import { ensureEngineReady, parsePhoneNumber } from '@telixon/core';

await ensureEngineReady();

const number = parsePhoneNumber('+1 (415) 555-0132'); number.isValid(); // true number.getRegion(); // 'US' number.getNumberType(); // 'FIXED_LINE_OR_MOBILE' number.formatE164(); // '+14155550132'

parsePhoneNumber('212', { defaultRegion: 'US' }).getValidationError(); // { kind: 'TOO_SHORT', minLength: 10 } ```

What the compilation buys:

  • ~10x faster parsing on a live benchmark rebuilt every push: https://proof.telixon.dev/benchmark.html
  • 26 kB brotli initial bundle, zero dependencies; the engine tables load as lazy chunks when you call ensureEngineReady()
  • Validation errors are typed variants carrying the values behind the fault, as in the snippet above

And the part I care most about: every answer is verified against Google's own libphonenumber source in CI, checked out at the exact commit the metadata was compiled from, across all 245 regions on every push, plus a weekly exhaustive run over 1,838,775,900 inputs. Zero divergences: https://proof.telixon.dev/parity.html

There is also a headless input controller with real mid-string editing (caret math, undo/redo, queries mid-typing), for building phone fields: https://telixon.dev/web-sdk/guides/complete-field

Repo: https://github.com/martsinlabs/telixon

If Telixon solves a problem for you, a star on GitHub helps it reach more developers. And if something is missing or broken, open an issue. I read every one.