From 3c4019a15443d0ba593022171e950a13f9f2ae41 Mon Sep 17 00:00:00 2001 From: Baris Aydek Date: Tue, 25 Feb 2025 19:28:28 +0300 Subject: [PATCH] nip54 normalizeIdentifier function --- index.ts | 1 + jsr.json | 1 + nip54.test.ts | 42 ++++++++++++++++++++++++++++++++++++++++++ nip54.ts | 19 +++++++++++++++++++ package.json | 5 +++++ 5 files changed, 68 insertions(+) create mode 100644 nip54.test.ts create mode 100644 nip54.ts diff --git a/index.ts b/index.ts index 2113e78..69aef00 100644 --- a/index.ts +++ b/index.ts @@ -21,6 +21,7 @@ export * as nip39 from './nip39.ts' export * as nip42 from './nip42.ts' export * as nip44 from './nip44.ts' export * as nip47 from './nip47.ts' +export * as nip54 from './nip54.ts' export * as nip57 from './nip57.ts' export * as nip59 from './nip59.ts' export * as nip98 from './nip98.ts' diff --git a/jsr.json b/jsr.json index 43f1070..e8d44aa 100644 --- a/jsr.json +++ b/jsr.json @@ -34,6 +34,7 @@ "./nip44": "./nip44.ts", "./nip46": "./nip46.ts", "./nip49": "./nip49.ts", + "./nip54": "./nip54.ts", "./nip57": "./nip57.ts", "./nip58": "./nip58.ts", "./nip59": "./nip59.ts", diff --git a/nip54.test.ts b/nip54.test.ts new file mode 100644 index 0000000..f01a90d --- /dev/null +++ b/nip54.test.ts @@ -0,0 +1,42 @@ +import { describe, test, expect } from 'bun:test' +import { normalizeIdentifier } from './nip54.ts' + +describe('normalizeIdentifier', () => { + test('converts to lowercase', () => { + expect(normalizeIdentifier('HELLO')).toBe('hello') + expect(normalizeIdentifier('MixedCase')).toBe('mixedcase') + }) + + test('trims whitespace', () => { + expect(normalizeIdentifier(' hello ')).toBe('hello') + expect(normalizeIdentifier('\thello\n')).toBe('hello') + }) + + test('normalizes Unicode to NFKC form', () => { + // é can be represented as single char é (U+00E9) or e + ´ (U+0065 U+0301) + expect(normalizeIdentifier('café')).toBe('café') + expect(normalizeIdentifier('cafe\u0301')).toBe('café') + }) + + test('replaces non-alphanumeric characters with hyphens', () => { + expect(normalizeIdentifier('hello world')).toBe('hello-world') + expect(normalizeIdentifier('user@example.com')).toBe('user-example-com') + expect(normalizeIdentifier('$special#chars!')).toBe('-special-chars-') + }) + + test('preserves numbers', () => { + expect(normalizeIdentifier('user123')).toBe('user123') + expect(normalizeIdentifier('2fast4you')).toBe('2fast4you') + }) + + test('handles multiple consecutive special characters', () => { + expect(normalizeIdentifier('hello!!!world')).toBe('hello---world') + expect(normalizeIdentifier('multiple spaces')).toBe('multiple---spaces') + }) + + test('handles Unicode letters from different scripts', () => { + expect(normalizeIdentifier('привет')).toBe('привет') + expect(normalizeIdentifier('こんにちは')).toBe('こんにちは') + expect(normalizeIdentifier('مرحبا')).toBe('مرحبا') + }) +}) diff --git a/nip54.ts b/nip54.ts new file mode 100644 index 0000000..badcc86 --- /dev/null +++ b/nip54.ts @@ -0,0 +1,19 @@ +export function normalizeIdentifier(name: string): string { + // Trim and lowercase + name = name.trim().toLowerCase() + + // Normalize Unicode to NFKC form + name = name.normalize('NFKC') + + // Convert to array of characters and map each one + return Array.from(name) + .map(char => { + // Check if character is letter or number using Unicode ranges + if (/\p{Letter}/u.test(char) || /\p{Number}/u.test(char)) { + return char + } + + return '-' + }) + .join('') +} diff --git a/package.json b/package.json index c5b2235..a6e0bce 100644 --- a/package.json +++ b/package.json @@ -173,6 +173,11 @@ "require": "./lib/cjs/nip49.js", "types": "./lib/types/nip49.d.ts" }, + "./nip54": { + "import": "./lib/esm/nip54.js", + "require": "./lib/cjs/nip54.js", + "types": "./lib/types/nip54.d.ts" + }, "./nip57": { "import": "./lib/esm/nip57.js", "require": "./lib/cjs/nip57.js",