Kaffeine

Extending JavaScript for fun and profit Download on Github

Kaffeine is a set of extensions to the JavaScript syntax that attempt to make it nicer to use. It compiles directly into JavaScript that is very similar, readable and line for line equivalent to the input (for easy debugging).

Kaffeine can be compiled to JavaScript offline, or as needed in a browser. Offline compiler support is provided via Node, and you can also use Kaffeine to power Node server apps.

How does it compare with CoffeeScript?

Kaffeine and CoffeeScript are similar in that they both compile to plain JavaScript code that runs in a browser or JS server environment. However, the design decisions underpinning Kaffeine are different to CoffeeScript:

Why is line-for-line important?

Not all JavaScript compilers respect the line numbering of your original source code. When the result runs perfectly, no problem, but this change in vertical layout has a dire effect on debugging. For instance, if something goes wrong on Line 475 of a randomly compiled program, how would anyone know where the problem was? Kaffeine addresses this by maintaining a strict 1:1 line ratio.

Overview

arrow function alias

Kaffeine supports a simple arrow as an alias to a function call.

Braces are optional for one liners and also an empty argument list can be omitted

Binding arrow =>

Kaffeine includes a convenience utility for binding a function to the current scope:

Interpolated strings and multiline

Kaffeine supports interpolation in the strings via the #{} operator

Interpolation can be sutextareassed by a backslace, e.g. "#{xx}"

... also supports multiline text

Kaffeine inserts newlines here to make the text output as it looks, but to prohibit the extra newlines - use the normal JavaScript backslash:

Ruby-style symbols

Ruby style symbols are converted to strings. Symbols are useful for easily observing which values are _state_ and which are output such as HTML or logging. They don’t share Ruby’s immutabilty (i.e. you can still perform string operations on them).

Unwrapping async calls with ! (bang)

A ! postfix to a function call signals to Kaffeine that this is an unwrapped async call masquerading as a normal function call. Kaffeine will recompile it into a normal function call with the follow code wrapping into an async callback:

is super useful for simplifying nested asynchronous calls (esp with nodejs) and works nicely in a number of scenarios.

When does the function unwrapping ‘stop’?

@ in bang function calls

In the case of unwrapped async calls via the bang postfix, @ will actually refer to the outer this.

Since we can refer to both via this method, binding becomes unnecessary:

for loop extensions

Kaffeine adds the extra keywords of for looping through arrays and the from keyword to avoid methods that are not direct members.

Kaffeine also provides a second optional second parameter for the in, of and from keywords, containing the current value:

Optional brackets

Kaffeine provides support for optional Brackets In Function Calls and for certain keywords

keywords such as for and if can omit their brackets (as long as the statement does not become amiguous). The brackets are inserted either before a newline, a left brace ‘{’ or a comma (for one liners)

this, this.constructor

This module provides an Ruby style aliases for:

Hash Alias

# is a shortcut for referring to the first argument in a function. Useful for terse function definitions:

Additionally, #n refers to the nth argument (n >= 0).

.= (dot equals) and ||= (OR equals)

2 extra assignment operators, ||= and .=. They work in a similar method as += etc.

Using keyword

The using keyword imports functions from an object into the current scope. For example if we have a library called "ninja" which exposes two methods jump and kick.

If we only wanted to import jump, we could write:

Note: that the * form uses eval, so it won’t work with ES5 strict, and also be careful putting it in sections of code that are often called.

Classes

Kaffeine provides support for simple class inheritence, super and friends

:: Operator

:: provides a shortcut to the prototype. For brevity, the :: operator on its own will reference the most recently assigned function:

Unix-style function calling via | (pipe)

This is probably one of the most unusual features of Kaffeine. It provides an alternative calling method than can be used for chaining (UNIX style passing). The _ variable must be set to a object of functions, which is used as a lookup.

It is very useful for ruby style enumeration chaining without using prototypes, and other utilities, particuliarily underscore library:

Default arguments

This feaure allows support for ruby-syle defaults for null or undefined arguments. Note, this uses non strict comparison with null, meaning falsy values such as 0 or "" can be used as defaults.

Implicit return

Kaffeine's arrow function syntax juices up the function-calling process by determining a completion value based on the last statement in the block, and returning that automatically.

The last statement of a function defined with -> will be automagically returned. For example

This will only work for returnable statements, i.e. variables, objects and functions. So an final if statement will result no return value

Note: this will be added in a future version. See Roadmap

Gotcha: be careful with using function arrow syntax with constructors

A constructor function won't work properly if it returns an array or an object. To avoid mistakenly creating a dud constructor, you can either fall back to using the function keyword, or opt-in to Kaffeine's class keyword, which offers enhanced inheritance support.

English comparison operators

The english words is, or, not, and, isnt are converted to the keywords ===, ||, !, && !== respecively.

Note that the conversion will not occur if they occur next to an operator, meaning that these keywords can still be used as variable identifiers, although it's not recommended. For examples, you can still write:

Implicit variable declaration

This module provides support for omitting the var keyword: the variables will be automagically defined in the closest relevant closure.

Examples

The var will be pulled to the top of the current closure:

Explicit assigment with var

It’s possible to explicity declare a variable to a function scope if you don’t want to trample over a variable in outer scope:

Installation and Use

npm install kaffeine

Ideas going forward

Array comprehensions

auto-slice arguments

Within any function, a reference to arguments will be auto-converted to a sliced version (meaning it can be used as a proper array object).

Existential ? operator

extend implicit return through if blocks