Original fork by @bolinfest http://bolinfest.com/coffee/features.html who added Closure Library support.
Forked from @smhanov https://github.com/smhanov/coffee-script who removed the need to use the Closure Library.
This fork's purpose is to allow developers to type-check CoffeeScript/Backbone/Underscore projects with full backwards compatibility and minimal JSDoc annotations.
Type checking uses the Google Closure Compiler with Advanced Optimizations mode. Type information is added using Google Closure type-checking JSDoc annotations. Closure Mode helps by adding annotations automatically by using CoffeeScript syntax.
I use vanilla CoffeeScript for compiling production/debug code, but use this fork with jzbuild for occasional type-checking.
There is no intention to integrate this back into the master branch.
This function allows us to repurpose the default parameter CoffeeScript feature to specify type information while not breaking your code when it is compiled with vanilla CoffeeScript.
Closure Mode parses the default parameter to look for type information. If this fails, this method passes along the default parameter as normal. If there is type information, we return undefined
unless there is a default parameter specified.
###* @param {*} a ###
###* @param {*} [b] ###
window.__ = (a, b) ->
return b if b?
if a.indexOf('{') is 0
and if a.substr(-1) is '}'
return undefined
else
return a
When you have a custom object like {foo: 'bar'}
used in a few places you should create an alias for it like so.
###* @typedef {{ foo: string }} ###
FooBar;
When passing options or other arguments to Backbone you need to provide a constructor.
class Foo extends Backbone.View
constructor: (options) ->
You must add type annotations to optional types like this:
###* @param {*} [name] ###
foo = (name) ->
or...
###* @param {*=} name ###
or we pass it to our magic function __()
that is recognized by Closure Mode returns undefined...
foo = (name = __('{*=}') ->
or we infer the type from the value...
foo = (name = __('foo'))
If a param does not have a default value
foo = (name = '{*=}') ->
otherwise...
foo = (name = __('{*=}', 'foo'))
When using something like this at the top of your classes:
Foo ?= {}
Foo.Bar ?= {}
Modify it to:
do -> Foo ?= {} Foo.Bar ?= {}
If something is continuously giving you warnings/errors use:
###* @suppress {checkTypes} ###
See here for different options.
@constructor
and @extends
annotations automatically added to class
declarations
Use --closure_infer
Adds inline annotations to optional function parameters based on the type of the default parameter.
class Foo
constructor: (bar = '{string=}')
Generates...
/**
* @constructor
* @param {string=} bar
*/
Foo = function(bar) {
if bar == null {
bar = '{string=}'
}
}
Array
I like this one a lot:
foo = (name = +string) ->
foo = (name =+ string) ->
foo = (name =+ )
foo = (name =+ num) ->
Or:
Add function(new:String,*)
for each inline param - this is unlikely
foo = (name = String, name = String.Opt)
foo = (name = String, name = String[s])
foo = (name = String, name = Opt(String))
foo = (name = String, name = Opt(String))
foo = (name = String, name = Array[String])
foo = (name = String, name = Object[String,Number]})
foo = (name =+ tString('hello'), name = tArray[(tString, tNumber)->])
foo = (name =+ _String('hello'), name = _Array[_String, _Number])
These are some more ideas:
foo = (name = '{string}'.type()) ->
foo = (name = '{string}'.default('foo')) ->
foo = (name = 'foo'.t('{?string=}')) ->
foo = (name = '{string}'._()) ->
foo = (name = '{string}'._('foo')) ->
foo = (name = string()) ->
foo = (name = 'foo'.string()) ->
foo = (name = (1).number()) ->
foo = (name = 'Foo.Bar'.type()) ->
foo = (name = (__ '{string}')) ->
foo = (name = (__ '{string}', 'foo')) ->
foo = (name = __['{string}']) ->
foo = (name = t('{string}')) ->
foo = name
Or:
Implement a special short-hand CoffeeScript JavaDoc:
# @name string
# @date Date
# =string
foo = (name = 1,date=+Date()
'hello'
- Better inline annotations based on identifier not just
- Allow adding params by annotating the initialize method in Backbone
- Automatic @return
- Hack, hack, hack
git checkout lib/*.js && bin/cake build && bin/cake build:parser && ./test-closure.sh
For interactive testing try: open closure/demo/index.html
To compile extras/coffee-script.js
run MINIFY=false bin/cake build:browser
Use rewriter.coffee
for modifying tokens before they are parsed by the lexer
Modify grammar.coffee
to accomodate new tokens
Modify compileNode()
method which actually writes out the code for each node