The last time Hackerfall tried to access this page, it returned a not found error. A cached version of the page is below, or clickhereto continue anyway

GitHub - laino/designtojs: A small extension of JS that makes writing today's code much faster

DEPRECATION WARNING: PROJECT IS NOT ACTIVELY MAINTAINED

DesignToJS

### Install it!
sudo npm -g install "git://github.com/binlain/designtojs.git#master"
### Compile an example!
designtojs example.djs > example.js

Quick examples: Events, Async.js

A small but powerful extension of the JavaScript language with a compiler written in the same. It is fully compatible with vanilla JavaScript (and you can even mix it freely), but it adds some syntactic sugar and useful helpers.

Overview

DesignToJS aims to improve readability and maintainability of JavaScript without being overly intrusive. You'll be used to the syntax in mere minutes, and probably love it even sooner.

Addresses JavaScript pain factors:

Keywords:

Index

DesignToJS

Documentation

Tools

Examples:

Asynchronous Code

Have a look at this DesignToJS example, which reads and prints a file in node.js:

printFile: (path, callback) {
    fs.readFile(path) -> (error! callback, contents)
    console.log(contents);
    callback();
}

Compiling it results in the following JavaScript code:

function printFile(path, callback){
    fs.readFile(path, function(error, contents){
        if(error != null){ 
            return callback(error);
        }
        console.log(contents);
        callback();
    });
}

(The code is beautified. By default everything will be arranged in a way that preserves the original line numbers.)

Argument Magic:

The following function greets you with your name, calling you 'Tim' if you don't provide on. It also says something nice about your age, if given. Even though you don't need to give your name or age, providing your city is required.

sayHello: (name: 'Tim', age?, city) {
    console.log('Hello to ' + city + ', ' + name);
    
    if(age){
        console.log('It\'s nice to be '+age+' years old');
    } else {
        console.log('You didn\'t tell me your age');
    }
}

The example above compiles to the following JavaScript code:

function sayHello(name, age, city) {
    if(arguments.length < 3){
        city = age;
        age = undefined;
    }
    if(name == null){
        name = 'Tim';
    }
    console.log('Hello to ' + city + ', ' + name);
    
    if(age){
        console.log('It\'s nice to be '+age+' years old');
    } else {
        console.log('You didn\'t tell me your age');
    }
}

The Callback Pyramid Of Hell (TM):

We have heard of it, the callback pyramid of doom/hell. Most will be used to seeing this kind of code:

function doThing(arg, callback){
   someFunction(arg, function(error, result){
       if(error) return callback(error);
       someOtherFunction(result, function(error, result){
           if(error) return callback(error);
           someThirdFunction(result, function(error, result){
               if(error) return callback(error);
               callback(null, result + 5);
           })
       })
   })
}

But no more! With DesignToJS it can simply be expressed like this!

doThing: (arg, callback) {
    someFunction(arg) -> (error! callback, result)
    someOtherFunction(result) -> (error! callback, result)
    someThirdFunction(result) -> (error! callback, result)
    callback(null, result+5);
}

Isn't that a beautiful way to do concurrency?

The old fashioned way

The code above will wrap the entire remaining function in a callback. But sometimes (often?) you need to do callbacks the old fashioned way. Of course that is still possible (except now it looks much nicer).

printFile: (path, callback) {
    fs.readFile(path) -> (error! callback, contents) {
        console.log(contents);
        callback();
    }
    console.log('Reading file...');
}

The example compiles to the following code:

function printFile(path, callback){
    fs.readFile(path, function(error, contents){
        if(error != null) {
            return callback(error);
        }
        console.log(contents);
        callback();
    });
    console.log('Reading file...');
}

Intuitive, isn't it? Did you see how we passed the error to the callback with barely a few characters of code?

Classes:

Creating classes in JavaScript has always been a repetitive exercise of figuring out how often you can type 'prototype' in a row without making a mistake. And as if to mock your efforts the resulting code wasn't even pretty. Luckily we can kiss that goodbye.

Car: (color: 'red'){
    this.color = color;
}

Car.drive: (what: 'highway'){
    console.log('A car of '+ this.color +' is driving along the '+ what )
}

This nicely unfolds to providing us with exactly the code we wanted:

function Car(color){
    if(color == null){
        color = 'red';
    }
    this.color = color;
}

Car.prototype.drive = function(what){
    if(what == null){
        what = 'highway';
    }
    console.log('A '+ this.color +' car is driving along the '+ what )
}

###Inheritance

Now what about inheritance? Of course that is possible too. Let's build a street-view car!

GoogleCar <= Car: (color){
    parent(color);
}

GoogleCar.drive: (){
    console.log('A '+ this.color +' car is driving the wrong way on a one-way road.')
}

Easy, isn't it? And all without having to bother with any of the languages that wanted to fix JavaScript, but ended up creating an entirely new language with its own set of problems.

Let's write the JavaScript we all love.

Documentation

Functions:

A function is created with the following syntax:

[Name [<= Parent]:] [*]([arg1, arg2, ...]) { ... }

Prototype Access

Functions on the prototype of another function can easily be created using this syntax:

Name.Property: ([arg1, arg2, ...]) { ... }

The above expression will expand to:

Name.prototype.Property = function([arg1, arg2, ...]){ ... }

Callbacks:

The '->' callback operator appends the right-side argument as last the last argument to the left-side function call.

asyncFunction([arg1, arg2, ...]) -> variable | function

Example using an anonymous function:

asyncFunction(arg1, arg2) -> (error, arg1, arg2) { ... }

Example using a variable

asyncFunction(arg1, arg2) -> callback

Automatic Binding:

If the right-side argument is an anonymous function that is not surrounding by any other statements, it will be automatically bound to the current 'this' context.

//Bound to 'this':
asyncFunction(arg1, arg2) -> (error, arg1, arg2) { ... }

//Not bound:
asyncFunction(arg1, arg2) -> ((error, arg1, arg2) { ... })
asyncFunction(arg1, arg2) -> callback
asyncFunction(arg1, arg2) -> (error, arg1, arg2) { ... }.bind(anything)
asyncFunction(arg1, arg2) -> (error, arg1, arg2) { ... }.anything

Note: If the compiler detects that 'this' is not used in the callback function, it may not output the bind statement.

Function Arguments:

DesignToJS adds some useful operators that can be used on function arguments.

'Default' Operator:

Allows you to define a default value for an argument. The default value applies if the argument is either undefined or null.

Syntax:

arg: default

'Should not' Operator:

If the argument is not null and not undefined, the function will return immediately and call the given callback function with the argument. You can also insert custom code before the argument.

Syntax:

arg! [code; ...;][callback]

'Optional' Operator:

Makes the marked element optional. A function can only have one optional operator. If the rightmost argument is not given, all other function arguments will be shifted so only the optional argument remains undefined. If you defined a default, the argument will be set to the default instead.

Syntax:

arg? [default]

Example:

example(arg1, arg2? 3, arg3, arg4){ ... }

If arg4 would be empty, arg4 would be set to arg3, arg3 to arg2 and arg2 to 3.

Tools

Syntax Highlighting:

####VIM:

You can use normal JavaScript syntax highlighting in VIM. To enable it for .djs files, simply add the following to your .vimrc:

au BufNewFile,BufRead *.djs set filetype=javascript

If you haven't already, comment the out the following out of your vimrc

" filetype plugin indent on

Leaving it enabled may break automatic indentation in some cases.

Linting:

Have a look at 'autojshint' in tools/. It's a bash script that can be used as a replacement for jshint/jslint. It will automatically convert the input file to normal JavaScript that can be used with the linter. By default it uses JSHint, but can be configured to use almost anything else.

####VIM:

To use it with VIM's syntastic plugin, add the following to your .vimrc:

let g:syntastic_javascript_checkers = ['jshint']
" let g:syntastic_javascript_jshint_args = "-c ~/.jshintrc"
let g:syntastic_jshint_exec = '/path/to/autojshint'

You'll need to change 'jshint_exec' to the path of your autojshint script.

Continue reading on github.com