/** * Builds obj from unicode emoji-test text * @reference https://unicode.org/Public/emoji/14.0/emoji-test.txt * @reference http://www.unicode.org/reports/tr51/ * * @example deno run --allow-net fetch-emoji.ts */ type Qualification = "fully-qualified" | "minimally-qualified" | "unqualified"; interface EmojiObj { emoji: string; version: number; name: string; qualification: Qualification; codepoints: string[]; ln?: string; } interface Results { [groupName: string]: { [subgroupName: string]: EmojiObj[]; }; } const version = "14.0"; const response = await fetch( `https://unicode.org/Public/emoji/${version}/emoji-test.txt`, ); const text = await response.text(); const groups = text.split("# group: "); groups.shift(); const results: Results = {}; groups.forEach((group) => { const [rawGroupName, ...subgroups] = group.split("# subgroup: "); const groupName = rawGroupName.replace("\n\n", ""); results[groupName] = {}; subgroups.map((subgroup) => { const [subgroupName, ...emojis] = subgroup.split("\n"); const emojiObjs = emojis .map((ln): EmojiObj => { const [_, codepoints, qualification, emoji, version, name] = ln.match( /^(.*);(.*)#(.*)E(\S*)\s(.*)/, ) || []; return { emoji: (emoji || "").trim(), version: Number(version), name: name, qualification: (qualification || "").trim() as Qualification, codepoints: (codepoints || "").trim().split(/\s+/), // ln: ln, }; }) .filter((emojiObj) => emojiObj.emoji && emojiObj.qualification === "fully-qualified" ); results[groupName][subgroupName] = emojiObjs; }); }); console.log(results);