namecode

Punycode for variable names

Reversible encoding from arbitrary Unicode to valid identifiers. O(n). No dependencies beyond unicode-ident.

Inputencode()
foofooAlready valid — identity
cafécaféValid Unicode identifier — identity
hello world_N_helloworld__fa0bSpace is not XID_Continue
foo-bar_N_foobar__da1dHyphen is not XID_Continue
123foo_N_123fooDigit is not XID_Start
_N_test_N__N_testPrefix collision

Identity

Valid identifiers pass through unchanged. encode(s) == s when s is already UAX 31.

Roundtrip

decode(encode(s)) == s for all strings. encode(decode(s)) == s for all valid encodings.

Idempotent

encode(encode(s)) == encode(s). Encoding an already-encoded string is a no-op.

Cross-language

Output conforms to UAX 31. Valid in Rust, Go, Python, and JavaScript.

cargo add namecode
use namecode::{encode, decode};

let encoded = encode("hello world");
assert_eq!(encoded, "_N_helloworld__fa0b");
assert_eq!(decode(&encoded).unwrap(), "hello world");