NPM Food - Emojis + NPM Packaging

March 11, 2017
javascript

npm install -g food

If we installed this package from NPM, what do we expect this to do? What kind of interface would we expect this to implement? I’m not quite sure; This was one of those ideas that I had a spark of an idea and started four years ago. Watching the package go stale and be empty for years reminded me I should try and provide another valuable node package to the world.

Original Intent

When I started out in 2013, I had an idea of creating a module that generated data for apps. When we created JavaScript apps, we want to populate our views with data but also check the boundaries of our app. I had no idea four years ago that the technical term was fuzzing and something like faker was what I was hoping to create. Later on I learned big list of naughty strings and I wanted to incorporate it with an easy way to test these strings. (Yay more food!)

What Now

After first learning how to publish npm packages way back when. (It’s as simple as npm publish!) it was still empty. I wanted to brush up on creating packages and was recently inspired by Jon New’s post on Unicode in Javascript to create a fun easy way to work with it.

Data

The Unicode Consortium hosts a repo of all the emojis possible in this file directory. I grabbed the emoji-test.txt and wrote a python parser to scrape and categorize all the emojis into json.

Beware Hacky Python Below!

"""
Stanley Zheng
March 11, 2017
Parses http://unicode.org/Public/emoji/4.0/emoji-test.txt
"""

import os
from collections import defaultdict, namedtuple

emojis = defaultdict(list)

emoji = namedtuple("emoji", ['unicode', "display", "category", "description"])

def parse_line(l, category):
    """
    Example of a line being parsed ...

        1F601  ; fully-qualified     # 😁 grinning face with smiling eyes
    """
    if len(l.split(';')) < 2:
        return None
    left, right = l.split(';')  # split on ;
    unicode = left.strip()
    if unicode == "0023 FE0F 20E3":
        display = "#"
        descript = "keycap: #" # special exception for # character
    else:
        right = right.split("#")[1] # more clean up
        display = right.split(' ')[1]
        descript = right[3:].strip('\n ')
    return emoji(unicode, display, category, descript)._asdict()



with open("data/emoji-test.txt", "r") as f:
         namespace = ""
         start = False
         for line in f.readlines():
            if "# subgroup: " in line[:12]:
                namespace = line[12:].strip('\n')
            elif start and len(line) > 1:
                emojis[namespace].append(parse_line(line, namespace))
            if "# group: Smileys & People" in line  :
                start = True

emojis.keys()

Post Processing

After this beautiful processing, we’re left with an keyed dictionary all the individual emojis with their plain text representation. I ran into issues serializing it into JSON because of the way python represents Unicode is different from Javascript.

For an Unicode character like “👋”, in Python I would get something like "\\1F44B\\1F3FC" but the interpretation in JavaScript would need to look something like "\u{1F44B}". So I wrote my own pretty printer and went to town with good ole copy paste.

from pprint import pprint

for _, cat in emojis.items():
    for e in cat:
        if e is None:
            continue
        print("""{{
          "unicode": "{unicode}",
          "display": "{display}",
          "description": "{description}",
          "category": "{category}"
        }},""".format(**e))

The finished product can be found on github here.

Packaging for NPM

Having not written a package in a while, I checked out one of my prolific goto people to see a good architecture to setup my package. Sindresorhus has some good defaults that I’m glad I was able to start from. Including setting up text fixtures using Ava test runner and linting using Xo. I put together a Readme on my project and hit publish. (one or more times).

Npm enforcement of semver meant everytime you wanted to publish a small change to your package, its recommended you publish a MAJOR/MINOR/PATCH scheme. See SemVer to learn a little bit more about this.

Summing up

Well, I released food to the world 🎉. Anyone with npm installed now can access my creation with npm install -g food. I’m still not sure where I want to take this next, so if you have a fun direction to take or add to this interface file an issue! This was a fun break from interview prep and reviewing if I remember anything about node modules and packaging. It’s like riding a bike and I always appreciate how easy it is for anyone to contribute and add their code to the world.

To end

➜  blog git:(master) ✗ food wave-hand-bye
[ { unicode: '1F44B 1F3FC',
    display: '👋🏼',
    description: 'waving hand: medium-light skin tone',
    category: 'body' },
  { unicode: '1F44B 1F3FD',
    display: '👋🏽',
    description: 'waving hand: medium skin tone',
    category: 'body' },
  { unicode: '1F44B 1F3FE',
    display: '👋🏾',
    description: 'waving hand: medium-dark skin tone',
    category: 'body' },
  { unicode: '1F919 1F3FC',
    display: '🤙🏼',
    description: 'call me hand: medium-light skin tone',
    category: 'body' },
  { unicode: '1F919 1F3FD',
    display: '🤙🏽',
    description: 'call me hand: medium skin tone',
    category: 'body' } ]