emoji-encoder/app/encoding.ts
2025-02-08 11:59:03 -05:00

62 lines
1.9 KiB
TypeScript

// Variation selectors block https://unicode.org/charts/nameslist/n_FE00.html
// VS1..=VS16
const VARIATION_SELECTOR_START = 0xfe00;
const VARIATION_SELECTOR_END = 0xfe0f;
// Variation selectors supplement https://unicode.org/charts/nameslist/n_E0100.html
// VS17..=VS256
const VARIATION_SELECTOR_SUPPLEMENT_START = 0xe0100;
const VARIATION_SELECTOR_SUPPLEMENT_END = 0xe01ef;
export function toVariationSelector(byte: number): string | null {
if (byte >= 0 && byte < 16) {
return String.fromCodePoint(VARIATION_SELECTOR_START + byte)
} else if (byte >= 16 && byte < 256) {
return String.fromCodePoint(VARIATION_SELECTOR_SUPPLEMENT_START + byte - 16)
} else {
return null
}
}
export function fromVariationSelector(codePoint: number): number | null {
if (codePoint >= VARIATION_SELECTOR_START && codePoint <= VARIATION_SELECTOR_END) {
return codePoint - VARIATION_SELECTOR_START
} else if (codePoint >= VARIATION_SELECTOR_SUPPLEMENT_START && codePoint <= VARIATION_SELECTOR_SUPPLEMENT_END) {
return codePoint - VARIATION_SELECTOR_SUPPLEMENT_START + 16
} else {
return null
}
}
export function encode(emoji: string, text: string): string {
// convert the string to utf-8 bytes
const bytes = new TextEncoder().encode(text)
let encoded = emoji
for (const byte of bytes) {
encoded += toVariationSelector(byte)
}
return encoded
}
export function decode(text: string): string {
let decoded = []
const chars = Array.from(text)
for (const char of chars) {
const byte = fromVariationSelector(char.codePointAt(0)!)
if (byte === null && decoded.length > 0) {
break
} else if (byte === null) {
continue
}
decoded.push(byte)
}
let decodedArray = new Uint8Array(decoded)
return new TextDecoder().decode(decodedArray)
}