From f61494059a0f587bcf383e9458be975a6dd6b015 Mon Sep 17 00:00:00 2001 From: Michael Kessler Date: Fri, 2 Nov 2012 00:04:38 +0100 Subject: [PATCH] Add trivial AMD module dependency management. 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")() --- CHANGELOG.md | 4 ++++ README.md | 51 ++++++++++++++++++++++++++++++++++++++++++ src/cli/command.coffee | 29 +++++++++++++++++------- src/haml-coffee.coffee | 48 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 122 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0044b9a..b3d5d4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/README.md b/README.md index 998a646..0ed308e 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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 diff --git a/src/cli/command.coffee b/src/cli/command.coffee index 5a40daa..f1d3f33 100644 --- a/src/cli/command.coffee +++ b/src/cli/command.coffee @@ -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' @@ -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' @@ -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 diff --git a/src/haml-coffee.coffee b/src/haml-coffee.coffee index 10e404c..a87af65 100644 --- a/src/haml-coffee.coffee +++ b/src/haml-coffee.coffee @@ -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] 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 @@ -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 @@ -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) """ @@ -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