Skip to content

Commit

Permalink
Add trivial AMD module dependency management.
Browse files Browse the repository at this point in the history
This allows to define global module dependencies,
which will be added to the `define` method.

The default value '{ hc: 'hamlcoffee' }' will add the
following to the module definition:

     define ['hamlcoffee'], (hc) ->

 When the template contains a require call in the form of

     - require 'module'
     - require 'deep/nested/other'

it will be added to the module definition list

     define ['hamlcoffee', 'module', 'deep/nested/other'], (hc, module, other) ->

allowing you to render a partial template:

    != module()
    != other()

 Of course the require call can have different quotes or
 parenthesises, allowing you to directly require and render:

   != require("another/other")()
  • Loading branch information
netzpirat committed Nov 1, 2012
1 parent c6edd9f commit f614940
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 10 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Master

* [haml_coffee_assets issue #74](https://github.com/netzpirat/haml_coffee_assets/issues/74): Add AMD dependency management.

# Version 1.6.2, October 26, 2012

* [#42](https://github.com/netzpirat/haml-coffee/issues/42) Ensure HTML5 `data` attribute format is correct.
Expand Down
51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,18 @@ Possible values are:
Wraps the template function into a `define()` statement to allow async
loading via AMD.

See AMD support for more information.

### Module dependencies

* Name: `dependencies`
* Type: `Object`
* Default: `{ hc: 'hamlcoffee' }`

The `dependencies` option allows you to define the modules that must be required for the AMD template `define` function.
The object key will be the function parameter name of the module the object value defines. See AMD support for more
information.

### Custom helper function options

Haml Coffee provides helper functions for HTML escaping, value cleaning and whitespace preservation, which must be
Expand Down Expand Up @@ -656,6 +668,45 @@ The `customSurround`, `customSucceed` and `customPrecede` are bound to the templ
You can find a default implementation for all these helper functions in
[Haml Coffee Assets](https://github.com/netzpirat/haml_coffee_assets/blob/master/vendor/assets/javascripts/hamlcoffee.js.coffee.erb).

## AMD support

* Global dependencies
* Trivial dependency detection

Haml Coffee has built in AMD support by setting the `placement` option to `amd`. This will generate a module definition
for the JavaScript template. The `dependencies` options can be used to provide a mapping of module names to parameters.
To illustrate this, the default value will result in the following module declaration:

```CoffeeScript
define ['hamlcoffee'], (hc) ->
```

When the template contains a require call in the form of

```CoffeeScript
- require 'module'
- require 'deep/nested/other'
```

it will be added to the module definition list

```CoffeeScript
define ['hamlcoffee', 'module', 'deep/nested/other'], (hc, module, other) ->
```

allowing you to render a partial template:

```CoffeeScript
!= module()
!= other()
```

Of course the require call can have different quotes or parenthesises, allowing you to directly require and render:

```CoffeeScript
!= require("another/other")()
```

## Development information

Haml-Coffee uses [Guard](https://github.com/guard/guard) for development, which you can install Guard with the Ruby
Expand Down
29 changes: 21 additions & 8 deletions src/cli/command.coffee
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
CoffeeMaker = require './coffee-maker'
fs = require 'fs'
findit = require 'findit'
CoffeeScript = require 'coffee-script'
CoffeeMaker = require './coffee-maker'
fs = require 'fs'
findit = require 'findit'

red = '\u001b[31m'
green = '\u001b[32m'
Expand All @@ -27,33 +28,38 @@ argv = require('optimist')
describe : 'Set a custom template name'
)
.options('b',
alias : 'basename',
alias : 'basename'
boolean : true
default : false
describe : 'Ignore file path when generate the template name'
)
.options('f',
alias : 'format',
alias : 'format'
default : 'html5'
describe : 'Set HTML output format, either `xhtml`, `html4` or `html5`'
)
.options('u',
alias : 'uglify',
alias : 'uglify'
boolean : true
default : false
describe : 'Do not properly indent or format the HTML output'
)
.options('e',
alias : 'extend',
alias : 'extend'
boolean : true
default : false
describe : 'Extend the template scope with the context'
)
.options('p',
alias : 'placement',
alias : 'placement'
default : 'global'
describe : 'Where to place the template function; one of: global, amd'
)
.options('d',
alias : 'dependencies'
default : "{ hc: 'hamlcoffee' }"
describe : 'The global template amd module dependencies'
)
.options('preserve',
default : 'pre,textarea'
describe : 'Set a comma separated list of HTML tags to preserve'
Expand Down Expand Up @@ -115,9 +121,16 @@ exports.run = ->
inputFilename = argv.i
templateName = argv.t
namespace = argv.n
dependencies = {}

try
dependencies = CoffeeScript.eval(argv.d)
catch err
console.error " #{ red }[Haml Coffee] Invalid dependencies:#{ reset } %s (%s)", argv.d, err

compilerOptions =
placement : argv.p
dependencies : dependencies
format : argv.f
uglify : argv.u
extendScope : argv.e
Expand Down
48 changes: 46 additions & 2 deletions src/haml-coffee.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module.exports = class HamlCoffee
#
# @param [Object] options the compiler options
# @option options [String] placement where to place the resultant function
# @option options [Array<String>] dependencies dependencies for the amd module
# @option options [Boolean] escapeHtml escape the output when true
# @option options [Boolean] escapeAttributes escape the tag attributes when true
# @option options [Boolean] cleanValue clean CoffeeScript values before inserting
Expand All @@ -37,6 +38,7 @@ module.exports = class HamlCoffee
#
constructor: (@options = {}) ->
@options.placement ?= 'global'
@options.dependencies ?= { hc: 'hamlcoffee' }
@options.escapeHtml ?= true
@options.escapeAttributes ?= true
@options.cleanValue ?= true
Expand Down Expand Up @@ -297,11 +299,32 @@ module.exports = class HamlCoffee
# define() statement for AMD.
#
_render_amd: ->
template = indent(@precompile(), 4)

modules = []
params = []

for param, module of @options.dependencies
modules.push module
params.push param

for param, module of @findDependencies(template)
modules.push module
params.push param

if modules.length isnt 0
modules = for m in modules
"'#{ m }'"

modules = "[#{ modules }], (#{ params.join(', ') })"
else
modules = ''

"""
define ->
define #{ modules } ->
(context) ->
render = ->
\n#{ indent(@precompile(), 4) }
\n#{ template }
render.call(context)
"""

Expand Down Expand Up @@ -557,3 +580,24 @@ module.exports = class HamlCoffee
".replace(/[\\s\\n]*\\u0091/mg, '').replace(/\\u0092[\\s\\n]*/mg, '')"
else
''

# Searches for AMD require statements to find
# all template dependencies.
#
# @example CST source code
# $o.push "" + $c require('assets/templates/test')() => { test: 'assets/templates/test' }
#
# @param [String] code the CoffeeScript template source code
# @return [Object] the module dependencies
#
findDependencies: (code) ->
requireRegexp = /require(?:\s+|\()(['"])(.+?)(\1)\)?/gm
dependencies = {}

while match = requireRegexp.exec code
module = match[2]
name = module.split('/').pop()

dependencies[name] = module

dependencies

0 comments on commit f614940

Please sign in to comment.