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

koffee

v1.20.0

Published

coffeescript clone

Readme

banner

koffee is a clone of Coffeescript with a few enhancements.

Constructor shortcut

class C
    @: ->           

... is an optional shortcut for ...

class C          
    constructor: -> 

Negative indexing

s = "abcde"

s[-1]        # -> 'e'
"abcde"[-2]  # -> 'd'
('cde')[-3]  # -> 'c'
[1,2,3][-2]  # -> 2

a = -2
s[a]         # -> undefined

v[-n] is a shortcut for v[-n..-n][0] for number literals n. Passing variables with negative values still returns undefined.

for ... in


for i in 0..5
    (a for a in 1+2...8) 

Square brackets around ranges in for ... in loops are optional.

Console shortcuts

log 'hello'  # -> hello
warn 'world' # -> world
error '!'    # -> !

Simple shortcuts for log, warn and error methods of console.

By the way, did I mention that all koffee features are individually toggleable? E.g., this one can be deactivated by passing the commandline flag --no-console-shortcut to the koffee command or by setting a flag in the options when calling module methods:

koffee = require 'koffee'
koffee.compile code, feature:console_shortcut:false

BigInt

a = 12345678901234567890n 
log a*a  # -> 152415787532388367501905199875019052100n

Optional commata

Coffeescript has a very nice way of initializing arrays:

a = [
   1
   2
   3
]

If you decide to join these into a single line, you have a problem: for each of the lines a comma must be inserted. The same goes for objects that span over multiple lines.

In koffee, you don't need to insert commata after number or string primitives and POD structures. Those are all valid expressions:

a = [ 1 2 3 ]           
a = { b:1 c:2 d:3 }   
a =   b:1 c:2 d:3
a =   b:[ c:2 'd' 3 ]  
a = [ [1 2] [d:3] ]

log 'a:' a , 'd:' 3      # some commas make sense :-)

describe 'something' ->
    it 'should' ->
    
on 'event' ->
on 'event' @myCallback

We are probably reaching the limits of minimalism here :)

Meta If

koffee allows you to control which blocks of code get compiled into JavaScript:

▸if false               # this block won't be compiled to .js
    code to             # 
    exclude from        # 
    compilation         # 

▸elif true              # this branch is switched on, so
    log 'hello'         # + these two lines 
    log 'world'         # + will be compiled
    
▸else                   # another ignored block
    null                # 

You can provide code in the condition, which will be evaluated at compile time

▸if os.platform()=='darwin' ▸then log 'mac' ▸else process.exit 0

will compile to

console.log("mac");

on macOS, on other platforms it will produce

process.exit(0);

Macros

If the condition part of ▸if starts with a , a lookup will be made into the compile options meta map. If a matching entry is found, the provided coffeescript blocks can be modified arbitrarily before they are written to JavaScript. When the macro is only operating on one block of code, you can omit the leading ▸if.

The default map includes some simple but useful macros that demonstrate this feature.

                                # log file position and object
▸dbg 'my object' a:1 b:2        # -> file:1 my object { a: 1, b: 2 }

▸assert 'message' condition     # log file position and message and exits if condition isn't truish
▸assert condition               # similar, but with 'assertion failure!' as the message
                                
                                # log execution times  
▸profile 'sum'                  # -> 8_4 1ms          line_column prefix
    ▸profile s1()               # -> 9_4 2ms          if not named
    ▸profile s2()               # -> sum 3ms

▸average 123                    # execute f and g 123 times and report average time
    f()                         # -> 11_0 321μs
    g()
    
▸start 'a'                      # like ▸profile, but lets you control
f = -> ▸end 'a'                 # when to start and stop timing
f()                             # -> a 824μs
    
▸test 'info'                    # will only be compiled if --test flag is set
    myTest()                    # includes logs for each test block

The unicode symbol can be substituted by ~>.

▸doc

This is a slightly special macro, because it's first pass is hardcoded in the tokenizer. The body of the macro is wrapped in a skinny triple string before further tokenization. It can contain anything except a '''.

In normal operation, it is reduced to the empty string. But if koffee is called with the --doc argument, logs will be inserted instead.

▸doc 'title'
    my documentation ...
log 'some code'
▸doc
    we are done.

koffee --doc file will output

## title
my documentation ...
some code
we are done.

but koffee file will only print some code

Config arguments

Still here? Nice!

The last feature might be easier to understand with a little bit of motivation up front:

Let's assume we need a function f, whose behavior should be configurable via it's arguments. Let's also assume that the configuration will probably grow or change a lot over time. It makes sense to use a config dictionary as the argument:

f = (cfg = a:1, b:2) -> log cfg

The default values are nicely visible, let's use it:

f()           # -> { a: 1, b: 2 }        
f a:4, b:8    # -> { a: 4, b: 8 }        All good so far.
f b:8, a:4    # -> { b: 8, a: 4 }        We can even change the order, nice!
                                         
f b:8         # -> { b: 8 }              Oops!

Crap! We have to provide all the arguments? That sucks!

We need a better solution. Let's use the destructuring feature of Coffeescript:

f = ({a=1, b=2}) -> log {a, b}   

The arguments look a bit ugly, and we need to provide an empty dictionary for the default behavior. But hey, we got nice variable names inside f now and it works as intended:

f {}          # -> { a: 1, b: 2 }  
f a:4, b:8    # -> { a: 4, b: 8 }  
f      b:8    # -> { a: 1, b: 8 }  
f a:8         # -> { a: 8, b: 2 }

Shortcut

koffee provides a nifty shortcut for this use case:

f = (a:1, b:2) -> log {a, b}  # Look, ma! The uglyness is gone :-)

The default values can be omitted:

f = (a:1, b:) -> log {a, b}

f {}          # -> { a: 1, b: null }
f b:2         # -> { a: 1, b: 2 }

Inheritance and super

Let's see what happens if we use this feature for method arguments.

class Base
    @: (@a:'Base') -> log @

class A extends Base
    @: (@a:'A') -> super

new A {}      # -> A { a: 'A' }

Note that the default value of a in A is not overridden by the one in Base.

Here the behavior of a super call without brackets differs from that of Coffeescript. While the original applies the arguments unmodified (and thereby missing the destructuring assignment), koffee does internally modify the arguments by inserting

arguments[0] = _.defaults {a:@a}, arguments[0]

immediately before applying super.

This will throw at runtime, if _.defaults is not defined. koffee simply assumes that either underscore or lodash is used.

Compatibility

So far, the koffee compiler output should be compatible with the latest version of Coffeescript on the version 1 branch.

The added features only use syntax that was invalid in CS1, so koffee should be able to compile any valid CS1 code. CS2 code should compile as well, but this is untested.

Some features have been changed or removed:

  • literal coffeescript is gone
  • kake and koffee work slightly different than cake and coffee
  • internal option parser replaced with nopt

npm package Build Status downloads