npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

esify

v15.1.2

Published

A CLI for converting Shopify’s CoffeeScript to ESNext.

Readme

esify

esify is a combination of various tools with the purpose of automatically translating Shopify’s CoffeeScript to ESNext. Unless you work at Shopify, you probably don’t need this.

Installation

npm install -g esify

Limitations

The tools on which esify is build have certain limitations that prevent us from providing the ideal conversion in some cases. We strongly recommend you have our linting configuration, eslint-plugin-shopify, set up for your project before beginning to translate in order to easily identify small translation errors (unused or missing references, indentation, etc). Below is a list of limitations that you should check for in the code you are converting:

  • All comments will be removed in the transformed output (including Sprockets directives)
  • CoffeeScript soak calls with embedded methods (e.g., foo.bar()?.baz) will compile to JavaScript that is hard to read
  • Assignment to a global outside of the file creating that global will result in incorrect exports (e.g., Shopify.UIPopover.foo = 'bar' outside the file declaring Shopify.UIPopover.foo)
  • Strings and regular expressions with complex escapes might be converted improperly
  • Multiline CoffeeScript strings become a single-line string with newlines inserted as needed
  • Object keys that use interpolation are not handled correctly.

Our CoffeeScript to JavaScript converter also makes a few assumptions that allow us to convert more files without user intervention, but which may not be true for your codebase:

  • Private variables inside of a class declaration are moved to the top of the scope in which the class is defined because JavaScript does not allow variables to be scoped to a class.

    class A
      b = 123
      c = () ->

    Becomes:

    var b = 123;
    var c = function() {};
    
    class A {}
  • Function calls executed in a class block are moved to the bottom of the scope, after the class’s definition. This can cause problems if the function call was made with the assumption that the prototype of the class has not yet been set up, as the JavaScript conversion will run after the class has been fully constructed.

    class A
      _.extend(@prototype, B)

    Becomes:

    class A {}
    _.extend(A.prototype, B);

Usage

From the root of the Shopify directory, run this script with a single, relative CoffeeScript file, or a glob pattern. Wait for it to finish, and marvel at the clean ESNext code that is spit out beside the original file! Note this script does not delete the original CoffeeScript file — you should review the output before pushing any changes.

esify app/assets/javascripts/admin/lib/*.coffee

You can provide custom options to esify by adding an esify.config.js file to the directory from which you are running the esify command. An example configuration is shown below:

// your-project/esify.config.js
var path = require('path');

module.exports = {
  // The global namespaces used in your current JavaScript code.
  appGlobalIdentifiers: ['Shopify'],

  // The root folder for your JavaScripts
  javaScriptSourceLocation: path.join(__dirname, 'app/assets/javascripts'),

  // The output style for your code. You can see all available options in the Recast docs:
  // https://github.com/benjamn/recast/blob/master/lib/options.js
  printOptions: {
    quote: 'single',
    trailingComma: true,
    tabWidth: 2,
    wrapColumn: 1000,
  },

  // The options for the mocha-context-to-global-reference shopify-codemod transform
  testContextToGlobals: {
    testClock: {
      properties: ['clock'],
      replace: true,
    },
    sandbox: {
      properties: ['spy', 'stub', 'mock', 'server', 'requests'],
    },
  },

  // A list of globals and their associated import paths for global-identifier-to-import
  globalIdentifiers: {
    _: 'lodash',
    $: 'jquery',
    moment: 'moment',
  },
  // A list of identifiers to rename for rename-identifier
  renameIdentifiers: {
    jQuery: '$',
  },
  // A list of identifiers and their properties that should be renamed for rename-property
  renameProperties: {
    _: {
      first: 'head',
      each: 'forEach',
      eachRight: 'forEachRight',
      entries: 'toPairs',
      entriesIn: 'toPairsIn',
      extend: 'assignIn',
      extendWith: 'assignInWith',
    },
  },
  // A list of object/ property pairs that always ignore return values of any
  // callbacks passed to them
  methodsThatIgnoreReturnValues: [
    {
      object: '_',
      methods: ['each'],
    },
    {
      object: /.*/,
      methods: ['forEach'],
    },
  ],
  // A list of object/ property pairs that always return undefined when called
  methodsReturningVoid: [
    {
      object: 'console',
      methods: ['log', 'warn'],
    },
    {
      object: /^(e|evt|event)$/,
      methods: ['preventDefault'],
    },
    {
      object: /.*/,
      methods: ['forEach'],
    },
    {
      object: '_',
      methods: ['each'],
    },
  ],
}