Skip to content

caffeine-suite/caffeine-script

Repository files navigation

logo Build Status NPM version

Why CaffeineScript and not JSX, TypeScript, CoffeeScript or JavaScript?

I believe less is more. It is the first principle of design and foundation of just about every good programming practice: DRY, KISS, ZEN (YAGNI), single responsibility principle, interface segregation, etc... That's why I wrote CaffeineScript. This info-graphic shows the result:

logo

2019 UPDATE: I'm using and developing CaffieneScript every day. Progress continues, the above example has been reduced to just 220 tokens. You can see more here: CaffeineScript TicTacToe

CaffeineScript, with the help of ArtSuite, takes 3x less code to write this complete implementation of Tic-Tac-Toe. In general, CaffeineScript is 3-5x more efficient than JSX, TypeScript or JavaScript. You can see 3x as much code on screen at once, solve problems with 3x less code, and have 3x less code to change when you need to refactor. Perhaps most important of all, you could have 3x less code to debug.

Code size matters. Less is more.

TicTacToe source:

TicTacToe live:

Of course, just because CaffeineScript can reduce code-size by 3x doesn't mean you'll be a full 3x faster. CaffeineScript cannot reduce the essential logic of your code. However, it dramatically cuts back the noise so you can see your core logic clearly.

Read more about programming with less:

JavaScript's Golden Heart

JavaScript has a golden heart. At its core, it is a powerful hybrid of object-oriented, functional and dynamically-typed languages. Combined with modern runtimes, world-class garbage collectors and JIT compilers, JavaScript can be a surprisingly good platform for building great applications.

However, JavaScript has an ailing body. Even now, in 2019, JavaScript has major syntax and semantic problems which make it error prone and dangerous. JavaScript's syntax is excessively verbose. Code readability matters, especially for large projects, and JavaScript's syntax is the least readable of any major language. This is easy to fix, and the rewards can be huge.

Further, JavaScript has many dangerous holes in its semantics which can introduce subtle, hard to find bugs. They include accidental globals, weakly-typed truth, weakly-typed equality and other weakly-typed operators. Thankfully, the core JavaScript semantics are good, and these auxiliary semantics can be partially or fully fixed without changing JavaScript.

CaffeineScript's goal is to maximize productivity for JavaScript-based projects. It does this primarily by minimizing syntax and patching the holes in JavaScript's semantics.

Inspired by CoffeeScript

I love CoffeeScript. I love the visual blocking of bracket-less blocks. As I used it over the years, though, I started noting it wasn't very consistent. I was frustrated by all-to-frequent edge cases where I had to revert to using brackets. For example, all array literals still require brackets ([]) in CoffeeScript. Eventually I couldn't stand it anymore. I set out to write a language that could parse bracket-less-blocks consistently.

If you love CoffeeScript, or even if you liked some parts but others drove you crazy, I've got an awesome language for you.

Introducing CaffeineScript

CaffeineScript is an open-source programming language that compiles to JavaScript. The goal is to minimize total effort, over a product's lifetime, for the entire team. Design thinking is essential for achieving that goal. That means user-experience and graphic design are as important as computer-science and software engineering. A well-designed language makes code more beautiful, programming more fun, and, ultimately, lets us get more done with less effort.

CaffeineScript starts where CoffeeScript left off, fixing its shortcomings and taking a big step forward for high-productivity JavaScript. Two concrete examples: improved React-style programming and 90% reduced module-specific code. The result is a lean, high-level language that empowers you to get the most out of JavaScript.

Example

CaffeineScript: logo

41 tokens in CaffeineScript - GitHub doesn't support custom syntax highlighting, so I've included the image above. You can access the example source here.

Logically equivalent JavaScript:

let {FluxComponent, Element} = require("art-suite");
let PlayerLine = require("./PlayerLine");

class PlayerList extends FluxComponent {
  render() {
    let
      currentPlayers = this.currentPlayers.sort( (a, b) => b.score - a.score ),
      children = [],
      {length} = currentPlayers;

    for (let i = 0; i < length; i++) {
      let player = currentPlayers[i];
      children.push(PlayerLine(player, { key: player.name }));
    }

    return Element({childrenLayout: "column"}, children);
  }
}

PlayerList.subscriptions("players.currentPlayers");

module.exports = PlayerList;

130 tokens in JavaScript

Related: ArtSuite

Live Demo

A brief, interactive slideshow written in CaffeineScript

Status: BETA

CaffeineScript is working and usable. The semantics and syntax may shift slightly as I work through the remaining bugs.

Install

npm install caffeine-script

Learn More

Contribute

More Examples

# CaffeineScript - 27 tokens and 0 must-match-tokens
import &ArtSuite

class Login extends Component

  render: ->
    Element
      TextElement
        text: :username
        size: ww: 1, hch: 1

      TextInput
        placeholder: "" enter username here
        size: ww: 1, hch: 1
// JavaScript - 73 tokens including 28 must-match-tokens
let {
  Component,
  Element,
  TextElement,
  TextInput
} = require('art-suite');

module.exports = class Login extends Component {
  render() {
    return Element(
      TextElement({
        text: 'username',
        size: {ww: 1, hch: 1}
      }),

      TextInput({
        placeholder: 'enter username here',
        size: {ww: 1, hch: 1}
      })
    );
  };
};
Implicit Array and Object literals
# CaffeineScript - 20 tokens
1d: 1 2 3 4 5 6 7 8 9

2d:
  1 2 3
  4 5 6
  7 8 9
// JavaScript - 54 tokens
{
  "1d": [1, 2, 3, 4, 5, 6, 7, 8, 9],
  "2d": [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
};
# CaffeineScript - 18 tokens - 0 must-match-tokens
users =
  id: 123 username: :shanebdavis born: 1976 fullName: "" Shane Brinkman-Davis Delamore
  id: 456 username: :alanturing  born: 1912 fullName: "" Alan Turing
// JavaScript - 35 tokens - 14 must-match tokens
let users = [
  {id: 123, username: "shanebdavis", born: 1976, "Shane Brinkman-Davis Delamore"},
  {id: 456, username: "alanturing",  born: 1912, "Alan Turing"}
];
# CaffeineScript - 15 tokens - 0 must-match-tokens
nameToColor:
  red:   #f00
  green: #0f0

colorToName:
  #f00:  :red
  #0f0:  :green

style:
  fontSize: 12pt
  padding:  25px
// JavaScript - 40 tokens - 24 must-match-tokens
{
  nameToColor: { red:      "#f00", green:   "#0f0"  },
  colorToName: { "#f00":   "red",  "#0f0":  "green" },
  style:       { fontSize: "12pt", padding: "25px"  }
};
# CaffeineScript 15 tokens - 2 must-match tokens
fontProps = object value, key from allProps when /^font/.test key
// JavaScript 44 tokens - 16 must-match tokens
var fontProps = {}, key, value;

for (key in allProps) {
  value = allProps[key];
  if (/^font/.test(key)) {
    fontProps[key] = value;
  }
}

What about TypeScript?

Is there interest in TypeScript support? If so, with some help, I could add it. CaffeineScript could easily support a modified TypeScript syntax for type annotation and integration into the TypeScript universe.

More on CaffeineScript and Static Typing

CaffeineScript and CoffeeScript

I owe a debt of gratitude to Jeremy Ashkenas and the CoffeeScript community. It is my primary inspiration, and what the CaffeineScript compiler was originally written in. More on inspirations from CoffeeScript: Coming from CoffeeScript.