@adraffy/ens-normalize

中文文档
1.11.1发布于 2025/09/19MITESM + CJS零依赖近 30 天下载 2319.9万

Ethereum Name Service (ENS) Name Normalizer

原始使用文档

ens-normalize.js

0-dependency Ethereum Name Service (ENS) Name Normalizer.

npm i @adraffy/ens-normalize ✓

import {ens_normalize} from '@adraffy/ens-normalize'; // or require()
// browser: https://cdn.jsdelivr.net/npm/@adraffy/ens-normalize@latest/dist/index.min.mjs (or .cjs)

// *** ALL errors thrown by this library are safe to print ***
// - characters are shown as {HEX} if should_escape()
// - potentially different bidi directions inside "quotes"
// - 200E is used near "quotes" to prevent spillover
// - an "error type" can be extracted by slicing up to the first (:)
// - labels are middle-truncated with ellipsis (…) at 63 cps

// string -> string
// throws on invalid names
// output ready for namehash
let normalized = ens_normalize('RaFFY🚴‍♂️.eTh');
// => "raffy🚴‍♂.eth"

// note: does not enforce .eth registrar 3-character minimum

Format names with fully-qualified emoji:

// works like ens_normalize()
// output ready for display
let pretty = ens_beautify('1⃣2⃣.eth'); 
// => "1️⃣2️⃣.eth"

// note: normalization is unchanged:
// ens_normalize(ens_beautify(x)) == ens_normalize(x)

Normalize name fragments for substring search:

// these fragments fail ens_normalize() 
// but will normalize fine as fragments
let frag1 = ens_normalize_fragment('AB--');    // expected error: label ext
let frag2 = ens_normalize_fragment('\u{303}'); // expected error: leading cm
let frag3 = ens_normalize_fragment('οо');      // expected error: mixture

Input-based tokenization:

// string -> Token[]
// never throws
let tokens = ens_tokenize('_R💩\u{FE0F}a\u{FE0F}\u{304}\u{AD}./');
// [
//     { type: 'valid', cps: [ 95 ] }, // valid (as-is)
//     {
//         type: 'mapped', 
//         cp: 82,         // input
//         cps: [ 114 ]    // output
//     }, 
//     { 
//         type: 'emoji',
//         input: Emoji(2) [ 128169, 65039 ],  // input 
//         emoji: [ 128169, 65039 ],           // fully-qualified
//         cps: Emoji(1) [ 128169 ]            // output (normalized)
//     },
//     {
//         type: 'nfc',
//         input: [ 97, 772 ],  // input (before nfc)
//         cps: [ 257 ],        // output (after nfc)
//         tokens0: [           // tokens (before nfc)
//             { type: 'valid', cps: [ 97 ] },
//             { type: 'ignored', cp: 65039 },
//             { type: 'valid', cps: [ 772 ] }
//         ],
//         tokens: [            // tokens (after nfc)
//             { type: 'valid', cps: [ 257 ] }
//         ]
//     },
//     { type: 'ignored', cp: 173 },
//     { type: 'stop', cp: 46 },
//     { type: 'disallowed', cp: 47 }
// ]

// note: if name is normalizable, then:
// ens_normalize(ens_tokenize(name).map(token => {
//     ** convert valid/mapped/nfc/stop to string **
// }).join('')) == ens_normalize(name)

Output-based tokenization:

// string -> Label[]
// never throws
let labels = ens_split('💩Raffy.eth_');
// [
//   {
//     input: [ 128169, 82, 97, 102, 102, 121 ],  
//     offset: 0, // index of codepoint, not substring index!
//                // (corresponding length can be inferred from input)
//     tokens: [
//       Emoji(2) [ 128169, 65039 ],   // emoji
//       [ 114, 97, 102, 102, 121 ]    // nfc-text
//     ],
//     output: [ 128169, 114, 97, 102, 102, 121 ],
//     emoji: true,
//     type: 'Latin'
//   },
//   {
//     input: [ 101, 116, 104, 95 ],
//     offset: 7,
//     tokens: [ [ 101, 116, 104, 95 ] ],
//     output: [ 101, 116, 104, 95 ],
//     error: Error('underscore allowed only at start')
//   }
// ]

Generate a sorted array of (beautified) supported emoji codepoints:

// () -> number[][]
let emojis = ens_emoji();
// [
//     [ 2764 ],
//     [ 128169, 65039 ],
//     [ 128105, 127997, 8205, 9877, 65039 ],
//     ...
// ]

Determine if a character shouldn't be printed directly:

// number -> bool
should_escape(0x202E); // eg. RIGHT-TO-LEFT OVERRIDE => true

Determine if a character is a combining mark:

// number -> bool
is_combining_mark(0x20E3); // eg. COMBINING ENCLOSING KEYCAP => true

Format codepoints as print-safe string:

// number[] -> string
safe_str_from_cps([0x300, 0, 32, 97]); // "◌̀{00} a"
safe_str_from_cps(Array(100).fill(97), 4); // "aa…aa" => middle-truncated

Build

Security

版本与发布记录

@adraffy/ens-normalize 共发布 52 个版本,首次发布于 2021/11/22;过去 12 个月发布了 0 个版本。

版本发布日期距今
1.11.1latest2025/09/191.1 年前
1.11.02024/09/152 年前
1.10.12024/01/262 年前
1.10.02023/09/193 年前
1.9.42023/07/243 年前
1.9.22023/05/303 年前

关于 @adraffy/ens-normalize 的常见问题

@adraffy/ens-normalize 是什么?

Ethereum Name Service (ENS) Name Normalizer

如何安装 @adraffy/ens-normalize?

在项目目录运行 npm install @adraffy/ens-normalize,或使用 pnpm add / yarn add / bun add。

@adraffy/ens-normalize 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/adraffy__ens-normalize 是否存在。

@adraffy/ens-normalize 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@adraffy/ens-normalize 可以商用吗?

@adraffy/ens-normalize 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@adraffy/ens-normalize 的下载量有多少?

根据 npm 官方下载统计,@adraffy/ens-normalize 在 2026/10/05 – 2026/11/03 这 30 天内被下载 23,198,992 次,日均约 773,300 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@adraffy/ens-normalize 还在维护吗?

最新版本 1.11.1 发布于 2025/09/19(1.1 年前);至今共发布 52 个版本,其中过去 12 个月发布了 0 个;首次发布于 2021/11/22。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。