[Pkg-javascript-commits] [node-transformers] 01/02: Imported Upstream version 3.0.0

Leo Iannacone l3on-guest at moszumanska.debian.org
Wed May 7 13:53:40 UTC 2014


This is an automated email from the git hooks/post-receive script.

l3on-guest pushed a commit to branch master
in repository node-transformers.

commit 131619713c26255a8d3e66965b3147a6829ba1e0
Author: Leo Iannacone <l3on at ubuntu.com>
Date:   Wed May 7 10:52:29 2014 +0200

    Imported Upstream version 3.0.0
---
 .npmignore                                      |   2 +
 .travis.yml                                     |   3 +
 LICENSE                                         |  19 +
 README.md                                       | 139 ++++++
 history.md                                      |  85 ++++
 lib/shared.js                                   | 162 +++++++
 lib/transformers.js                             | 588 ++++++++++++++++++++++++
 package.json                                    |  67 +++
 test/fixtures/stylus/expected.css               |   4 +
 test/fixtures/stylus/sample.styl                |   3 +
 test/fixtures/uglify-js/script.js               |   6 +
 test/mocha.opts                                 |   1 +
 test/simple/atpl/sample-a.txt                   |   1 +
 test/simple/atpl/sample-b.txt                   |   1 +
 test/simple/cdata-css/sample-a-expected.txt     |   3 +
 test/simple/cdata-css/sample-a.txt              |   1 +
 test/simple/cdata-css/sample-b-expected.txt     |   3 +
 test/simple/cdata-css/sample-b.txt              |   1 +
 test/simple/cdata-js/sample-a-expected.txt      |   3 +
 test/simple/cdata-js/sample-a.txt               |   1 +
 test/simple/cdata-js/sample-b-expected.txt      |   3 +
 test/simple/cdata-js/sample-b.txt               |   1 +
 test/simple/cdata/sample-a-expected.txt         |   1 +
 test/simple/cdata/sample-a.txt                  |   1 +
 test/simple/cdata/sample-b-expected.txt         |   1 +
 test/simple/cdata/sample-b.txt                  |   1 +
 test/simple/coffee-script/sample-a-expected.txt |   6 +
 test/simple/coffee-script/sample-a.txt          |   1 +
 test/simple/coffee-script/sample-b-expected.txt |   6 +
 test/simple/coffee-script/sample-b.txt          |   1 +
 test/simple/coffeecup/sample-a-expected.txt     |   1 +
 test/simple/coffeecup/sample-a.txt              |   3 +
 test/simple/coffeecup/sample-b-expected.txt     |   1 +
 test/simple/coffeecup/sample-b.txt              |   3 +
 test/simple/cson/sample-a-expected.txt          |   1 +
 test/simple/cson/sample-a.txt                   |   9 +
 test/simple/cson/sample-b-expected.txt          |   1 +
 test/simple/cson/sample-b.txt                   |   9 +
 test/simple/dot/sample-a.txt                    |   1 +
 test/simple/dot/sample-b.txt                    |   1 +
 test/simple/dust/sample-a.txt                   |   1 +
 test/simple/dust/sample-b.txt                   |   1 +
 test/simple/eco/sample-a.txt                    |   1 +
 test/simple/eco/sample-b.txt                    |   1 +
 test/simple/ect/sample-a.txt                    |   1 +
 test/simple/ect/sample-b.txt                    |   1 +
 test/simple/ejs/sample-a.txt                    |   1 +
 test/simple/ejs/sample-b.txt                    |   1 +
 test/simple/escape-html/sample-a-expected.txt   |   1 +
 test/simple/escape-html/sample-a.txt            |   1 +
 test/simple/escape-html/sample-b-expected.txt   |   1 +
 test/simple/escape-html/sample-b.txt            |   1 +
 test/simple/haml-coffee/sample-a.txt            |   1 +
 test/simple/haml-coffee/sample-b.txt            |   1 +
 test/simple/haml/sample-a-expected.txt          |   2 +
 test/simple/haml/sample-a.txt                   |   1 +
 test/simple/haml/sample-b-expected.txt          |   2 +
 test/simple/haml/sample-b.txt                   |   1 +
 test/simple/handlebars/sample-a.txt             |   1 +
 test/simple/handlebars/sample-b.txt             |   1 +
 test/simple/hogan/sample-a.txt                  |   1 +
 test/simple/hogan/sample-b.txt                  |   1 +
 test/simple/jade/sample-a.txt                   |   1 +
 test/simple/jade/sample-b.txt                   |   1 +
 test/simple/jazz/sample-a.txt                   |   1 +
 test/simple/jazz/sample-b.txt                   |   1 +
 test/simple/jqtpl/sample-a.txt                  |   1 +
 test/simple/jqtpl/sample-b.txt                  |   1 +
 test/simple/just/sample-a.txt                   |   1 +
 test/simple/just/sample-b.txt                   |   1 +
 test/simple/less/sample-a-expected.txt          |  24 +
 test/simple/less/sample-a.txt                   |  50 ++
 test/simple/less/sample-b-expected.txt          |  24 +
 test/simple/less/sample-b.txt                   |  50 ++
 test/simple/liquor/sample-a.txt                 |   1 +
 test/simple/liquor/sample-b.txt                 |   1 +
 test/simple/markdown/sample-a-expected.txt      |   6 +
 test/simple/markdown/sample-a.txt               |   6 +
 test/simple/markdown/sample-b-expected.txt      |   6 +
 test/simple/markdown/sample-b.txt               |   6 +
 test/simple/mote/sample-a.txt                   |   1 +
 test/simple/mote/sample-b.txt                   |   1 +
 test/simple/mustache/sample-a.txt               |   1 +
 test/simple/mustache/sample-b.txt               |   1 +
 test/simple/plates/sample-a-expected.txt        |   1 +
 test/simple/plates/sample-a.txt                 |   1 +
 test/simple/plates/sample-b-expected.txt        |   1 +
 test/simple/plates/sample-b.txt                 |   1 +
 test/simple/qejs/sample-a.txt                   |   1 +
 test/simple/qejs/sample-b.txt                   |   1 +
 test/simple/sass/sample-a-expected.txt          |   8 +
 test/simple/sass/sample-a.txt                   |  11 +
 test/simple/sass/sample-b-expected.txt          |   8 +
 test/simple/sass/sample-b.txt                   |  11 +
 test/simple/stylus/sample-a-expected.txt        |   8 +
 test/simple/stylus/sample-a.txt                 |  10 +
 test/simple/stylus/sample-b-expected.txt        |   8 +
 test/simple/stylus/sample-b.txt                 |  10 +
 test/simple/swig/sample-a.txt                   |   1 +
 test/simple/swig/sample-b.txt                   |   1 +
 test/simple/templayed/sample-a.txt              |   1 +
 test/simple/templayed/sample-b.txt              |   1 +
 test/simple/toffee/sample-a.txt                 |   1 +
 test/simple/toffee/sample-b.txt                 |   1 +
 test/simple/uglify-css/sample-a-expected.txt    |   1 +
 test/simple/uglify-css/sample-a.txt             |   3 +
 test/simple/uglify-css/sample-b-expected.txt    |   1 +
 test/simple/uglify-css/sample-b.txt             |   3 +
 test/simple/uglify-json/sample-a-expected.txt   |   1 +
 test/simple/uglify-json/sample-a.txt            |   3 +
 test/simple/uglify-json/sample-b-expected.txt   |   1 +
 test/simple/uglify-json/sample-b.txt            |   5 +
 test/simple/underscore/sample-a.txt             |   1 +
 test/simple/underscore/sample-b.txt             |   1 +
 test/simple/verbatim/sample-a-expected.txt      |   1 +
 test/simple/verbatim/sample-a.txt               |   1 +
 test/simple/verbatim/sample-b-expected.txt      |   1 +
 test/simple/verbatim/sample-b.txt               |   1 +
 test/simple/walrus/sample-a.txt                 |   1 +
 test/simple/walrus/sample-b.txt                 |   1 +
 test/simple/whiskers/sample-a.txt               |   1 +
 test/simple/whiskers/sample-b.txt               |   1 +
 test/test.js                                    | 108 +++++
 test/update-package.js                          |  13 +
 124 files changed, 1590 insertions(+)

diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..cefaa67
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,2 @@
+test/
+.travis.yml
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..baa0031
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,3 @@
+language: node_js
+node_js:
+  - 0.8
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..dfb0b19
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2013 Forbes Lindesay
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5ea8ee4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,139 @@
+[![Build Status](https://travis-ci.org/ForbesLindesay/transformers.png?branch=master)](https://travis-ci.org/ForbesLindesay/transformers)
+# transformers
+
+  String/Data transformations for use in templating libraries, static site generators and web frameworks.  This gathers the most useful transformations you can apply to text or data into one library with a consistent API.  Transformations can be pretty much anything but most are either compilers or templating engines.
+
+## Supported transforms
+
+  To use each of these transforms you will also need to install the associated npm module for that transformer.
+
+### Template engines
+
+  - [atpl](http://documentup.com/soywiz/atpl.js) - Compatible with twig templates
+  - [coffeecup](http://documentup.com/gradus/coffeecup) - pure coffee-script templates (fork of coffeekup)
+  - [dot](http://documentup.com/olado/doT) [(website)](https://github.com/Katahdin/dot-packer) - focused on speed
+  - [dust](http://documentup.com/akdubya/dustjs) [(website)](http://akdubya.github.com/dustjs/) - asyncronous templates
+  - [eco](http://documentup.com/sstephenson/eco) - Embedded CoffeeScript templates
+  - [ect](http://documentup.com/baryshev/ect) [(website)](http://ectjs.com/) - Embedded CoffeeScript templates
+  - [ejs](http://documentup.com/visionmedia/ejs) - Embedded JavaScript templates
+  - [haml](http://documentup.com/visionmedia/haml.js) [(website)](http://haml-lang.com/) - dry indented markup
+  - [haml-coffee](http://documentup.com/netzpirat/haml-coffee/) [(website)](http://haml-lang.com/) - haml with embedded CoffeeScript
+  - [handlebars](http://documentup.com/wycats/handlebars.js/) [(website)](http://handlebarsjs.com/) - extension of mustache templates
+  - [hogan](http://documentup.com/twitter/hogan.js) [(website)](http://twitter.github.com/hogan.js/) - Mustache templates
+  - [jade](http://documentup.com/visionmedia/jade) [(website)](http://jade-lang.com/) - robust, elegant, feature rich template engine
+  - [jazz](http://documentup.com/shinetech/jazz)
+  - [jqtpl](http://documentup.com/kof/jqtpl) [(website)](http://api.jquery.com/category/plugins/templates/) - extensible logic-less templates
+  - [JUST](http://documentup.com/baryshev/just) - EJS style template with some special syntax for layouts/partials etc.
+  - [liquor](http://documentup.com/chjj/liquor) - extended EJS with significant white space
+  - [mustache](http://documentup.com/janl/mustache.js) - logic less templates
+  - [QEJS](http://documentup.com/jepso/QEJS) - Promises + EJS for async templating
+  - [swig](http://documentup.com/paularmstrong/swig) [(website)](http://paularmstrong.github.com/swig/) - Django-like templating engine
+  - [templayed](http://documentup.com/archan937/templayed.js/) [(website)](http://archan937.github.com/templayed.js/) - Mustache focused on performance
+  - [toffee](http://documentup.com/malgorithms/toffee) - templating language based on coffeescript
+  - [underscore](http://documentup.com/documentcloud/underscore) [(website)](http://documentcloud.github.com/underscore/)
+  - [walrus](http://documentup.com/jeremyruppel/walrus) - A bolder kind of mustache
+  - [whiskers](http://documentup.com/gsf/whiskers.js/tree/) - logic-less focused on readability
+
+### Stylesheet Languages
+
+  - [less](http://documentup.com/cloudhead/less.js) [(website)](http://lesscss.org/) - LESS extends CSS with dynamic behavior such as variables, mixins, operations and functions.
+  - [stylus](http://documentup.com/learnboost/stylus) [(website)](http://learnboost.github.com/stylus/) - revolutionary CSS generator making braces optional
+  - [sass](http://documentup.com/visionmedia/sass.js) [(website)](http://sass-lang.com/) - Sassy CSS
+
+### Minifiers
+
+  - [uglify-js](http://documentup.com/mishoo/UglifyJS2) - No need to install anything, just minifies/beautifies JavaScript
+  - [uglify-css](https://github.com/visionmedia/css) - No need to install anything, just minifies/beautifies CSS
+  - ugilify-json - No need to install anything, just minifies/beautifies JSON
+
+### Other
+
+  - cdata - No need to install anything, just wraps input as `<![CDATA[${INPUT_STRING]]>` with the standard escape for `]]>` (`]]]]><![CDATA[>`).
+  - cdata-js - as `cdata`, but with surrounding comments suitable for inclusion into a HTML/JavaScript `<script>` block: `//<![CDATA[\n${INPUT_STRING\n//]]>`.
+  - cdata-css - as `cdata`, but with surrounding comments suitable for inclusion into a HTML/CSS `<style>` block: `/*<![CDATA[*/\n${INPUT_STRING\n/*]]>*/`.
+  - verbatim - No need to install anything, acts as a verbatim passthrough `${INPUT_STRING}`
+  - escape-html - No need to install anything, just replaces special characters to sanitize input for html/xml
+  - [coffee-script](http://coffeescript.org/) - `npm install coffee-script`
+  - [cson](https://github.com/bevry/cson) - coffee-script based JSON format
+  - markdown - You can use `marked`, `supermarked`, `markdown-js` or `markdown`
+
+Pull requests to add more transforms will always be accepted providing they are open-source, come with unit tests, and don't cause any of the tests to fail.
+
+## API
+
+  The exported object `transformers` is a collection of named transformers.  To access an individual transformer just do:
+
+  ```javascript
+  var transformer = require('transformers')['transformer-name']
+  ```
+
+### Transformer
+
+  The following options are given special meaning by `transformers`:
+
+   - `filename` is set by transformers automatically if using the `renderFile` APIs.  It is used if `cache` is enabled.
+   - `cache` if true, the template function will be cached where possible (templates are still updated if you provide new options, so this can be used in most live applications).
+   - `sudoSync` used internally to put some asyncronous transformers into "sudo syncronous" mode.  Don't touch this.
+   - `minify` if set to true on a transformer that isn't a minifier, it will cause the output to be minified.  e.g. `coffeeScript.renderSync(str, {minify: true})` will result in minified JavaScript.
+
+#### Transformer.engines
+
+  Returns an array of engines that can be used to power this transformer.  The first of these that's installed will be used for the transformation.
+
+  To enable a transformation just take `[engine] = Transformer.engines[0]` and then do `npm install [engine]`.  If `[engine]` is `.` there is no need to install an engine from npm to use the transformer.
+
+#### Transformer.render(str, options, cb)
+
+  Tranform the string `str` using the `Transformer` with the provided options and call the callback `cb(err, res)`.
+
+  If no `cb` is provided, this method returns a [promises/A+](http://promises-aplus.github.com/promises-spec/) promise.
+
+#### Transformer.renderSync(str, options)
+
+  Synchronous version of `Transformer.render`
+
+#### Transformer.renderFile(filename, options, cb)
+
+  Reads the file at filename into `str` and sets `options.filename = filename` then calls `Transform.render(str, options, cb)`.
+
+  If no `cb` is provided, this method returns a [promises/A+](http://promises-aplus.github.com/promises-spec/) promise.
+
+#### Tranformer.renderFileSync(filename, options)
+
+  Synchronous version of `Tranformer.renderFile`
+
+#### Transformer.outputFormat
+
+  A string, one of:
+
+   - `'xml'`
+   - `'css'`
+   - `'js'`
+   - `'json'`
+   - `'text'`
+
+Adding to this list will **not** result in a major version change, so you should handle unexpected types gracefully (I'd suggest default to assuming `'text'`).
+
+#### Transformer.sync
+
+  `true` if the transformer can be used syncronously, `false` otherwise.
+
+## Libraries that don't work synchronously
+
+  The following transformations will always throw an exception if you attempt to run them synchronously:
+
+   1. dust
+   2. qejs
+   3. html2jade
+
+The following transformations sometimes throw an exception if run syncronously, typically they only throw an exception if you are doing something like including another file.  If you are not doing the things that cause them to fail then they are consistently safe to use syncronously.
+
+   - jade (only when using `then-jade` instead of `jade`)
+   - less (when `@import` is used with a url instead of a filename)
+   - jazz (When one of the functions passed as locals is asyncronous)
+
+The following libraries look like they might sometimes throw exceptions when used syncronously (if you read the source) but they never actually do so:
+
+   - just
+   - ect
+   - stylus
\ No newline at end of file
diff --git a/history.md b/history.md
new file mode 100644
index 0000000..0692613
--- /dev/null
+++ b/history.md
@@ -0,0 +1,85 @@
+## 3.0.0 - 2014-02-12
+
+ - **escape-html**
+ - remove **html2jade** (it was all round problematic and not kept up to date with recent changes to jade)
+ - remove **component-js** and **component-css** (I don't think they are very useful to have here, browserify is better)
+ - improve **stylus** support
+ - fix **mustache** (it no longer supports caching properly)
+
+## 2.1.0 - 2013-07-13
+
+ - **verbatim**
+ - **cdata-js**
+ - **cdata-css**
+ - fix escaping in **cdata**
+ - fix **less** errors
+
+## 2.0.1 - 2013-04-22
+
+ - Fix global leak of `exportscoffeeScript` (test still fails because `jade` requires an out of date version of `transformers`)
+
+## 2.0.0 - 2013-03-31
+
+ - Add `minify` support to all transformers
+ - Bundle minifiers in package
+
+## 1.8.3 - 2013-03-19
+
+ - Update promise dependency
+
+## 1.8.2 - 2013-02-10
+
+ - Support `sourceURLs` in **component**
+
+## 1.8.1 - 2013-02-10
+
+ - Add travis-ci
+ - FIX **toffee** support which was broken by their latest update
+ - FIX lookup paths for **component** weren't set so you couldn't build components with dependancies
+
+## 1.8.0 - 2013-01-30
+
+ - **highlight** (needs tests)
+
+## 1.7.0 - 2013-01-30
+
+ - **component-js**
+ - **component-css**
+ - **html2jade** - must be `v0.0.7` because of a bug in later versions
+ - Much more extensive tests
+
+## 1.6.0 - 2013-01-29
+
+ - **uglify-css**
+ - **uglify-json**
+ - Rename **uglify** to **uglify-js**
+
+## 1.5.0 - 2013-01-27
+
+ - **dot**
+
+## 1.4.0 - 2013-01-25
+
+ - Support sync `@import` statements in **less**
+ - Report real errors from **less** (rather than objects)
+
+## 1.3.0 - 2013-01-25
+
+ - **templayed**
+ - **plates**
+
+## 1.2.1 - 2013-01-09
+
+ - make **markdown** work when using **markdown** as the engine (**marked** is the recommended engine).
+
+## 1.2.0 - 2013-01-09
+
+ - **js** (pass through)
+ - **css** (pass through)
+ - rename **coffee-script** from **coffee** to **coffee-script** and add **coffee** as an alias
+
+## 1.1.0 - 2013-01-08
+
+ - **coffeecup**
+ - **cson**
+ - FIX: disabling **dust** cache
\ No newline at end of file
diff --git a/lib/shared.js b/lib/shared.js
new file mode 100644
index 0000000..8663117
--- /dev/null
+++ b/lib/shared.js
@@ -0,0 +1,162 @@
+var Promise = require('promise');
+var fs = require('fs');
+var path = require('path');
+var normalize = path.normalize;
+
+
+Promise.prototype.nodeify = function (cb) {
+  if (typeof cb === 'function') {
+    this.then(function (res) { process.nextTick(function () { cb(null, res); }); },
+              function (err) { process.nextTick(function () { cb(err); }); });
+    return undefined;
+  } else {
+    return this;
+  }
+}
+
+var minifiers = {};
+
+module.exports = Transformer;
+function Transformer(obj) {
+  this.name = obj.name;
+  this.engines = obj.engines;
+  this.isBinary = obj.isBinary || false;
+  this.isMinifier = obj.isMinifier || false;
+  this.outputFormat = obj.outputFormat;
+  this._cache = {};
+  if (typeof obj.async === 'function') {
+    this._renderAsync = obj.async;
+    this.sudoSync = obj.sudoSync || false;
+  }
+  if (typeof obj.sync === 'function') {
+    this._renderSync = obj.sync;
+    this.sync = true;
+  } else {
+    this.sync = obj.sudoSync || false;
+  }
+
+  if (this.isMinifier)
+    minifiers[this.outputFormat] = this;
+  else {
+    var minifier = minifiers[this.outputFormat];
+    if (minifier) {
+      this.minify = function(str, options) {
+        if (options && options.minify)
+          return minifier.renderSync(str, typeof options.minify === 'object' && options.minify || {});
+        return str;
+      }
+    }
+  }
+}
+
+Transformer.prototype.cache = function (options, data) {
+  if (options.cache && options.filename) {
+    if (data) return this.cache[options.filename] = data;
+    else return this.cache[options.filename];
+  } else {
+    return data;
+  }
+};
+Transformer.prototype.loadModule = function () {
+  if (this.engine) return this.engine;
+  for (var i = 0; i < this.engines.length; i++) {
+    try {
+      var res = this.engines[i] === '.' ? null : (this.engine = require(this.engines[i]));
+      this.engineName = this.engines[i];
+      return res;
+    } catch (ex) {
+      if (this.engines.length === 1) {
+        throw ex;
+      }
+    }
+  }
+  throw new Error('In order to apply the transform ' + this.name + ' you must install one of ' + this.engines.map(function (e) { return '"' + e + '"'; }).join());
+};
+Transformer.prototype.minify = function(str, options) {
+  return str;
+}
+Transformer.prototype.renderSync = function (str, options) {
+  options = options || {};
+  options = clone(options);
+  this.loadModule();
+  if (this._renderSync) {
+    return this.minify(this._renderSync((this.isBinary ? str : fixString(str)), options), options);
+  } else if (this.sudoSync) {
+    options.sudoSync = true;
+    var res, err;
+    this._renderAsync((this.isBinary ? str : fixString(str)), options, function (e, val) {
+      if (e) err = e;
+      else res = val;
+    });
+    if (err) throw err;
+    else if (res != undefined) return this.minify(res, options);
+    else if (typeof this.sudoSync === 'string') throw new Error(this.sudoSync.replace(/FILENAME/g, options.filename || ''));
+    else throw new Error('There was a problem transforming ' + (options.filename || '') + ' syncronously using ' + this.name);
+  } else {
+    throw new Error(this.name + ' does not support transforming syncronously.');
+  }
+};
+Transformer.prototype.render = function (str, options, cb) {
+  options = options || {};
+  var self = this;
+  return new Promise(function (resolve, reject) {
+    self.loadModule();
+    if (self._renderAsync) {
+      self._renderAsync((self.isBinary ? str : fixString(str)), clone(options), function (err, val) {
+        if (err) reject(err);
+        else resolve(self.minify(val, options));
+      })
+    } else {
+      resolve(self.renderSync(str, options));
+    }
+  })
+  .nodeify(cb);
+};
+Transformer.prototype.renderFile = function (path, options, cb) {
+  options = options || {};
+  var self = this;
+  return new Promise(function (resolve, reject) {
+    options.filename = (path = normalize(path));
+    if (self._cache[path])
+      resolve(null);
+    else
+      fs.readFile(path, function (err, data) {
+        if (err) reject(err);
+        else resolve(data);
+      })
+  })
+  .then(function (str) {
+    return self.render(str, options);
+  })
+  .nodeify(cb);
+};
+Transformer.prototype.renderFileSync = function (path, options) {
+  options = options || {};
+  options.filename = (path = normalize(path));
+  return this.renderSync((this._cache[path] ? null : fs.readFileSync(path)), options);
+};
+function fixString(str) {
+  if (str == null) return str;
+  //convert buffer to string
+  str = str.toString();
+  // Strip UTF-8 BOM if it exists
+  str = (0xFEFF == str.charCodeAt(0) 
+    ? str.substring(1)
+    : str);
+  //remove `\r` added by windows
+  return str.replace(/\r/g, '');
+}
+
+function clone(obj) {
+  if (Array.isArray(obj)) {
+    return obj.map(clone);
+  } else if (obj && typeof obj === 'object') {
+    var res = {};
+    for (var key in obj) {
+      res[key] = clone(obj[key]);
+    }
+    return res;
+  } else {
+    return obj;
+  }
+}
diff --git a/lib/transformers.js b/lib/transformers.js
new file mode 100644
index 0000000..a608865
--- /dev/null
+++ b/lib/transformers.js
@@ -0,0 +1,588 @@
+var dirname = require('path').dirname;
+var Transformer = require('./shared');
+
+/**
+ * minifiers must be first in order to be incorporated inside instances of respective output formats
+ */
+var uglifyJS = require('uglify-js');
+exports.uglify = exports.uglifyJS = exports['uglify-js'] = new Transformer({
+  name: 'uglify-js',
+  engines: ['.'],
+  outputFormat: 'js',
+  isMinifier: true,
+  sync: function (str, options) {
+    options.fromString = true;
+    return this.cache(options) || this.cache(options, uglifyJS.minify(str, options).code);
+  }
+});
+var uglifyCSS = require('css');
+exports.uglifyCSS = exports['uglify-css'] = new Transformer({
+  name: 'uglify-css',
+  engines: ['.'],
+  outputFormat: 'css',
+  isMinifier: true,
+  sync: function (str, options) {
+    options.compress = options.compress != false && options.beautify != true;
+    return this.cache(options) || this.cache(options, uglifyCSS.stringify(uglifyCSS.parse(str), options));
+  }
+});
+
+exports.uglifyJSON = exports['uglify-json'] = new Transformer({
+  name: 'uglify-json',
+  engines: ['.'],
+  outputFormat: 'json',
+  isMinifier: true,
+  sync: function (str, options) {
+    return JSON.stringify(JSON.parse(str), null, options.beautify);
+  }
+});
+
+
+/**
+ * Syncronous Templating Languages
+ */
+
+function sync(str, options) {
+  var tmpl = this.cache(options) || this.cache(options, this.engine.compile(str, options));
+  return tmpl(options);
+}
+
+exports.swig = new Transformer({
+  name: 'swig',
+  engines: ['swig'],
+  outputFormat: 'xml',
+  sync: sync
+});
+
+exports.atpl = new Transformer({
+  name: 'atpl',
+  engines: ['atpl'],
+  outputFormat: 'xml',
+  sync: function sync(str, options) {
+    var tmpl = this.cache(options);
+    if (!tmpl) {
+      var cInfo = {cache: options.cache, filename: options.filename};
+      if (options.filename) {
+        delete options.filename; //atpl can't handle absolute windows file paths properly
+      }
+      tmpl = this.cache(cInfo, this.engine.compile(str, options));
+    }
+    return tmpl(options);
+  }
+});
+
+exports.dot = new Transformer({
+  name: 'dot',
+  engines: ['dot'],
+  outputFormat: 'xml',
+  sync: function sync(str, options) {
+    var tmpl = this.cache(options) || this.cache(options, this.engine.template(str));
+    return tmpl(options);
+  }
+});
+
+exports.liquor = new Transformer({
+  name: 'liquor',
+  engines: ['liquor'],
+  outputFormat: 'xml',
+  sync: sync
+});
+
+exports.ejs = new Transformer({
+  name: 'ejs',
+  engines: ['ejs'],
+  outputFormat: 'xml',
+  sync: sync
+});
+
+exports.eco = new Transformer({
+  name: 'eco',
+  engines: ['eco'],
+  outputFormat: 'xml',
+  sync: sync//N.B. eco's internal this.cache isn't quite right but this bypasses it
+});
+
+exports.jqtpl = new Transformer({
+  name: 'jqtpl',
+  engines: ['jqtpl'],
+  outputFormat: 'xml',
+  sync: function (str, options) {
+    var engine = this.engine;
+    var key = (options.cache && options.filename) ? options.filename : '@';
+    engine.compile(str, key);
+    var res = this.engine.render(key, options);
+    if (!(options.cache && options.filename)) {
+      delete engine.cache[key];
+    }
+    this.cache(options, true); // caching handled internally
+    return res;
+  }
+});
+
+exports.haml = new Transformer({
+  name: 'haml',
+  engines: ['hamljs'],
+  outputFormat: 'xml',
+  sync: sync
+});
+
+exports['haml-coffee'] = new Transformer({
+  name: 'haml-coffee',
+  engines: ['haml-coffee'],
+  outputFormat: 'xml',
+  sync: function (str, options) {
+    // https://github.com/netzpirat/haml-coffee/issues/91
+    if (global.CoffeeScript) delete global.CoffeeScript; //prevent global leak
+    var tmpl = this.cache(options) || this.cache(options, this.engine.compile(str, options));
+    return tmpl(options);
+  }
+});
+
+exports.whiskers = new Transformer({
+  name: 'whiskers',
+  engines: ['whiskers'],
+  outputFormat: 'xml',
+  sync: sync
+});
+
+exports.hogan = new Transformer({
+  name: 'hogan',
+  engines: ['hogan.js'],
+  outputFormat: 'xml',
+  sync: function(str, options){
+    var tmpl = this.cache(options) || this.cache(options, this.engine.compile(str, options));
+    return tmpl.render(options, options.partials);
+  }
+});
+
+exports.handlebars = new Transformer({
+  name: 'handlebars',
+  engines: ['handlebars'],
+  outputFormat: 'xml',
+  sync: function(str, options){
+    for (var partial in options.partials) {
+      this.engine.registerPartial(partial, options.partials[partial]);
+    }
+    var tmpl = this.cache(options) || this.cache(options, this.engine.compile(str, options));
+    return tmpl(options);
+  }
+});
+
+exports.underscore = new Transformer({
+  name: 'underscore',
+  engines: ['underscore'],
+  outputFormat: 'xml',
+  sync: function(str, options){
+    var tmpl = this.cache(options) || this.cache(options, this.engine.template(str));
+    return tmpl(options);
+  }
+});
+
+exports.walrus = new Transformer({
+  name: 'walrus',
+  engines: ['walrus'],
+  outputFormat: 'xml',
+  sync: function(str, options){
+    var tmpl = this.cache(options) || this.cache(options, this.engine.parse(str));
+    return tmpl.compile(options);
+  }
+});
+
+exports.mustache = new Transformer({
+  name: 'mustache',
+  engines: ['mustache'],
+  outputFormat: 'xml',
+  sync: function(str, options){
+    str = this.cache(options) || this.cache(options, str);
+    return this.engine.to_html(str, options, options.partials);
+  }
+});
+
+exports.templayed = new Transformer({
+  name: 'templayed',
+  engines: ['templayed'],
+  outputFormat: 'xml',
+  sync: function(str, options){
+    var tmpl = this.cache(options) || this.cache(options, this.engine(str));
+    return tmpl(options);
+  }
+});
+
+exports.plates = new Transformer({
+  name: 'plates',
+  engines: ['plates'],
+  outputFormat: 'xml',
+  sync: function(str, options){
+    str = this.cache(options) || this.cache(options, str);
+    return this.engine.bind(str, options, options.map);
+  }
+});
+
+exports.mote = new Transformer({
+  name: 'mote',
+  engines: ['mote'],
+  outputFormat: 'xml',
+  sync: sync
+});
+
+exports.toffee = new Transformer({
+  name: 'toffee',
+  engines: ['toffee'],
+  outputFormat: 'xml',
+  sync: function (str, options) {
+    var View = this.engine.view;
+    var v = this.cache(options) || this.cache(options, new View(str, options));
+    var res = v.run(options, require('vm').createContext({}));
+    if (res[0]) throw res[0];
+    else return res[1];
+  }
+});
+
+exports.coffeekup = exports.coffeecup = new Transformer({
+  name: 'coffeecup',
+  engines: ['coffeecup', 'coffeekup'],
+  outputFormat: 'xml',
+  sync: function (str, options) {
+    var compiled = this.cache(options) || this.cache(options, this.engine.compile(str, options));
+    return compiled(options);
+  }
+});
+
+/**
+ * Asyncronous Templating Languages
+ */
+
+exports.just = new Transformer({
+  name: 'just',
+  engines: ['just'],
+  outputFormat: 'xml',
+  sudoSync: true,
+  async: function (str, options, cb) {
+    var JUST = this.engine;
+    var tmpl = this.cache(options) || this.cache(options, new JUST({ root: { page: str }}));
+    tmpl.render('page', options, cb);
+  }
+});
+
+exports.ect = new Transformer({
+  name: 'ect',
+  engines: ['ect'],
+  outputFormat: 'xml',
+  sudoSync: true, // Always runs syncronously
+  async: function (str, options, cb) {
+    var ECT = this.engine;
+    var tmpl = this.cache(options) || this.cache(options, new ECT({ root: { page: str }}));
+    tmpl.render('page', options, cb);
+  }
+});
+
+exports.jade = new Transformer({
+  name: 'jade',
+  engines: ['jade', 'then-jade'],
+  outputFormat: 'xml',
+  sudoSync: 'The jade file FILENAME could not be rendered syncronously.  N.B. then-jade does not support syncronous rendering.',
+  async: function (str, options, cb) {
+    this.cache(options, true);//jade handles this.cache internally
+    this.engine.render(str, options, cb);
+  }
+})
+
+exports.dust = new Transformer({
+  name: 'dust',
+  engines: ['dust', 'dustjs-linkedin'],
+  outputFormat: 'xml',
+  sudoSync: false,
+  async: function (str, options, cb) {
+    var ext = 'dust'
+      , views = '.';
+
+    if (options) {
+      if (options.ext) ext = options.ext;
+      if (options.views) views = options.views;
+      if (options.settings && options.settings.views) views = options.settings.views;
+    }
+
+    this.engine.onLoad = function(path, callback){
+      if ('' == extname(path)) path += '.' + ext;
+      if ('/' !== path[0]) path = views + '/' + path;
+      read(path, options, callback);
+    };
+
+    var tmpl = this.cache(options) || this.cache(options, this.engine.compileFn(str));
+    if (options && !options.cache) this.engine.cache = {};//invalidate dust's internal cache
+    tmpl(options, cb);
+  }
+});
+
+exports.jazz = new Transformer({
+  name: 'jazz',
+  engines: ['jazz'],
+  outputFormat: 'xml',
+  sudoSync: true, // except when an async function is passed to locals
+  async: function (str, options, cb) {
+    var tmpl = this.cache(options) || this.cache(options, this.engine.compile(str, options));
+    tmpl.eval(options, function(str){
+      cb(null, str);
+    });
+  }
+});
+
+exports.qejs = new Transformer({
+  name: 'qejs',
+  engines: ['qejs'],
+  outputFormat: 'xml',
+  sudoSync: false,
+  async: function (str, options, cb) {
+    var tmpl = this.cache(options) || this.cache(options, this.engine.compile(str, options));
+    tmpl(options).done(function (result) {
+        cb(null, result);
+    }, function (err) {
+        cb(err);
+    });
+  }
+});
+
+/**
+ * Stylsheet Languages
+ */
+
+exports.less = new Transformer({
+  name: 'less',
+  engines: ['less'],
+  outputFormat: 'css',
+  sudoSync: 'The less file FILENAME could not be rendered syncronously.  This is usually because the file contains `@import url` statements.',
+  async: function (str, options, cb) {
+    var self = this;
+    if (self.cache(options)) return cb(null, self.cache(options));
+    if (options.filename) {
+      options.paths = options.paths || [dirname(options.filename)];
+    }
+    //If this.cache is enabled, compress by default
+    if (options.compress !== true && options.compress !== false) {
+      options.compress = options.cache || false;
+    }
+    if (options.sudoSync) {
+      options.syncImport = true;
+    }
+    var parser = new(this.engine.Parser)(options);
+    parser.parse(str, function (err, tree) {
+      try {
+        if (err) throw err;
+        var res = tree.toCSS(options);
+        self.cache(options, res);
+        cb(null, res);
+      } catch (ex) {
+        if (ex.constructor.name === 'LessError' && typeof ex === 'object') {
+          ex.filename = ex.filename || '"Unkown Source"';
+          var err = new Error(self.engine.formatError(ex, options).replace(/^[^:]+:/, ''), ex.filename, ex.line);
+          err.name = ex.type;
+          ex = err;
+        }
+        return cb(ex);
+      }
+    });
+  }
+});
+
+exports.styl = exports.stylus = new Transformer({
+  name: 'stylus',
+  engines: ['stylus'],
+  outputFormat: 'css',
+  sudoSync: true,// always runs syncronously
+  async: function (str, options, cb) {
+    var self = this;
+    if (self.cache(options)) return cb(null, self.cache(options));
+    if (options.filename) {
+      options.paths = options.paths || [dirname(options.filename)];
+    }
+
+    // If this.cache is enabled, compress by default
+    if (options.compress !== true && options.compress !== false) {
+      options.compress = options.cache || false;
+    }
+
+    // Utility function for cloning objects
+    function clone(obj){
+      if (obj == null || typeof(obj) != 'object') return obj;
+      var tmp = new obj.constructor(); 
+      for (var key in obj) tmp[key] = clone(obj[key]);
+      return tmp;
+    }
+
+    var initial = this.engine(str);
+
+    // Special handling for stylus js api functions
+    // given { define: { foo: 'bar', baz: 'quux' } }
+    // runs initial.define('foo', 'bar').define('baz', 'quux')
+    
+    var allowed = ['set', 'include', 'import', 'define', 'use'];
+    var special = {}
+    var normal = clone(options);
+    for (var v in options) {
+      if (allowed.indexOf(v) > -1) { special[v] = options[v]; delete normal[v]; }
+    }
+
+    // special options through their function names
+    for (var k in special) {
+      for (var v in special[k]) { initial[k](v, special[k][v]); }
+    }
+
+    // normal options through set()
+    for (var k in normal) {
+      for (var v in normal[k]) { initial['set'](v, normal[k][v]); }
+    }
+
+    initial.render(function (err, res) {
+      if (err) return cb(err);
+      self.cache(options, res);
+      cb(null, res);
+    });
+  }
+})
+
+exports.sass = new Transformer({
+  name: 'sass',
+  engines: ['sass'],
+  outputFormat: 'css',
+  sync: function (str, options) {
+    try {
+      return this.cache(options) || this.cache(options, this.engine.render(str));
+    } catch (ex) {
+      if (options.filename) ex.message += ' in ' + options.filename;
+      throw ex;
+    }
+  }
+});
+
+/**
+ * Miscelaneous
+ */
+
+exports.md = exports.markdown = new Transformer({
+  name: 'markdown',
+  engines: ['marked', 'supermarked', 'markdown-js', 'markdown'],
+  outputFormat: 'html',
+  sync: function (str, options) {
+    var arg = options;
+    if (this.engineName === 'markdown') arg = options.dialect; //even if undefined
+    return this.cache(options) || this.cache(options, this.engine.parse(str, arg));
+  }
+});
+
+
+exports.coffee = exports['coffee-script'] = exports.coffeescript = exports.coffeeScript = new Transformer({
+  name: 'coffee-script',
+  engines: ['coffee-script'],
+  outputFormat: 'js',
+  sync: function (str, options) {
+    return this.cache(options) || this.cache(options, this.engine.compile(str, options));
+  }
+});
+
+exports.cson = new Transformer({
+  name: 'cson',
+  engines: ['cson'],
+  outputFormat: 'json',
+  sync: function (str, options) {
+    return this.cache(options) || this.cache(options, JSON.stringify(this.engine.parseSync(str)));
+  }
+});
+
+exports.cdata = new Transformer({
+  name: 'cdata',
+  engines: ['.'],// `.` means "no dependency"
+  outputFormat: 'xml',
+  sync: function (str, options) {
+    var escaped = str.replace(/\]\]>/g, "]]]]><![CDATA[>");
+    return this.cache(options) || this.cache(options, '<![CDATA[' + escaped + ']]>');
+  }
+});
+
+exports["cdata-js"] = new Transformer({
+  name: 'cdata-js',
+  engines: ['.'],// `.` means "no dependency"
+  outputFormat: 'xml',
+  sync: function (str, options) {
+    var escaped = str.replace(/\]\]>/g, "]]]]><![CDATA[>");
+    return this.cache(options) || this.cache(options, '//<![CDATA[\n' + escaped + '\n//]]>');
+  }
+});
+
+exports["cdata-css"] = new Transformer({
+  name: 'cdata-css',
+  engines: ['.'],// `.` means "no dependency"
+  outputFormat: 'xml',
+  sync: function (str, options) {
+    var escaped = str.replace(/\]\]>/g, "]]]]><![CDATA[>");
+    return this.cache(options) || this.cache(options, '/*<![CDATA[*/\n' + escaped + '\n/*]]>*/');
+  }
+});
+
+exports.verbatim = new Transformer({
+  name: 'verbatim',
+  engines: ['.'],// `.` means "no dependency"
+  outputFormat: 'xml',
+  sync: function (str, options) {
+    return this.cache(options) || this.cache(options, str);
+  }
+});
+
+exports["escape-html"] = new Transformer({
+  name: 'escape-html',
+  engines: ['.'],// `.` means "no dependency"
+  outputFormat: 'xml',
+  sync: function (str, options) {
+    var escaped = str.replace(/&/g, '&')
+                     .replace(/</g, '<')
+                     .replace(/>/g, '>')
+                     .replace(/"/g, '"')
+                     .replace(/'/g, '&#x27;');
+
+    return this.cache(options) || this.cache(options, escaped);
+  }
+});
+
+exports['highlight'] = new Transformer({
+  name: 'highlight',
+  engines: ['highlight.js'],
+  outputFormat: 'xml',
+  sync: function (str, options, cb) {
+    if (this.cache(options)) return this.cache(options);
+    if (options.lang) {
+      try {
+        return this.cache(options, this.engine.highlight(options.lang, str).value);
+      } catch (ex) {}
+    }
+    if (options.auto || !options.lang) {
+      try {
+        return this.cache(options, this.engine.highlightAuto(str).value);
+      } catch (ex) {}
+    }
+    return this.cache(options, str);
+  }
+});
+
+
+/**
+ * Marker transformers (they don't actually apply a transformation, but let you declare the 'outputFormat')
+ */
+
+exports.css = new Transformer({
+  name: 'css',
+  engines: ['.'],// `.` means "no dependency"
+  outputFormat: 'css',
+  sync: function (str, options) {
+    return this.cache(options) || this.cache(options, str);
+  }
+});
+
+exports.js = new Transformer({
+  name: 'js',
+  engines: ['.'],// `.` means "no dependency"
+  outputFormat: 'js',
+  sync: function (str, options) {
+    return this.cache(options) || this.cache(options, str);
+  }
+});
+
+
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..99c0e12
--- /dev/null
+++ b/package.json
@@ -0,0 +1,67 @@
+{
+  "name": "transformers",
+  "version": "3.0.0",
+  "description": "String/Data transformations for use in templating libraries, static site generators and web frameworks",
+  "main": "lib/transformers.js",
+  "scripts": {
+    "pretest": "node test/update-package && npm install",
+    "test": "mocha"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/ForbesLindesay/transformers.git"
+  },
+  "author": "ForbesLindesay",
+  "license": "MIT",
+  "readmeFilename": "README.md",
+  "gitHead": "4b46e72cba3ad3403fd5ed3802d5472dcfa77311",
+  "devDependencies": {
+    "mocha": "~1.8",
+    "expect.js": "~0.2",
+    "swig": "*",
+    "atpl": "*",
+    "liquor": "*",
+    "ejs": "*",
+    "eco": "*",
+    "jqtpl": "*",
+    "hamljs": "*",
+    "haml-coffee": "*",
+    "whiskers": "*",
+    "hogan.js": "*",
+    "handlebars": "*",
+    "underscore": "*",
+    "walrus": "*",
+    "mustache": "*",
+    "mote": "*",
+    "toffee": "*",
+    "just": "*",
+    "ect": "*",
+    "jade": "*",
+    "then-jade": "*",
+    "dust": "*",
+    "dustjs-linkedin": "*",
+    "jazz": "*",
+    "qejs": "*",
+    "less": "*",
+    "stylus": "*",
+    "sass": "*",
+    "marked": "*",
+    "supermarked": "*",
+    "markdown-js": "*",
+    "markdown": "*",
+    "coffee-script": "*",
+    "cson": "*",
+    "coffeekup": "*",
+    "coffeecup": "*",
+    "templayed": "*",
+    "plates": "*",
+    "dot": "*",
+    "component-builder": "*",
+    "highlight.js": "*"
+  },
+  "dependencies": {
+    "promise": "~2.0",
+    "css": "~1.0.8",
+    "uglify-js": "~2.2.5"
+  }
+}
\ No newline at end of file
diff --git a/test/fixtures/stylus/expected.css b/test/fixtures/stylus/expected.css
new file mode 100644
index 0000000..210b8a6
--- /dev/null
+++ b/test/fixtures/stylus/expected.css
@@ -0,0 +1,4 @@
+p {
+  color: 'red';
+  test: 'bar';
+}
diff --git a/test/fixtures/stylus/sample.styl b/test/fixtures/stylus/sample.styl
new file mode 100644
index 0000000..8798e23
--- /dev/null
+++ b/test/fixtures/stylus/sample.styl
@@ -0,0 +1,3 @@
+p
+  color: custom_color
+  test: foo
diff --git a/test/fixtures/uglify-js/script.js b/test/fixtures/uglify-js/script.js
new file mode 100644
index 0000000..8a2f505
--- /dev/null
+++ b/test/fixtures/uglify-js/script.js
@@ -0,0 +1,6 @@
+(function (name) {
+  function hello(world) {
+    return 'Hello ' + world + '!';
+  }
+  return hello(name);
+}('Forbes Lindesay'));
\ No newline at end of file
diff --git a/test/mocha.opts b/test/mocha.opts
new file mode 100644
index 0000000..fb5f824
--- /dev/null
+++ b/test/mocha.opts
@@ -0,0 +1 @@
+--reporter spec
\ No newline at end of file
diff --git a/test/simple/atpl/sample-a.txt b/test/simple/atpl/sample-a.txt
new file mode 100644
index 0000000..f5b9962
--- /dev/null
+++ b/test/simple/atpl/sample-a.txt
@@ -0,0 +1 @@
+<p>{{user.name}}</p>
\ No newline at end of file
diff --git a/test/simple/atpl/sample-b.txt b/test/simple/atpl/sample-b.txt
new file mode 100644
index 0000000..3dcaa58
--- /dev/null
+++ b/test/simple/atpl/sample-b.txt
@@ -0,0 +1 @@
+<strong>{{user.name}}</strong>
\ No newline at end of file
diff --git a/test/simple/cdata-css/sample-a-expected.txt b/test/simple/cdata-css/sample-a-expected.txt
new file mode 100644
index 0000000..c6e2769
--- /dev/null
+++ b/test/simple/cdata-css/sample-a-expected.txt
@@ -0,0 +1,3 @@
+/*<![CDATA[*/
+hello world
+/*]]>*/
\ No newline at end of file
diff --git a/test/simple/cdata-css/sample-a.txt b/test/simple/cdata-css/sample-a.txt
new file mode 100644
index 0000000..95d09f2
--- /dev/null
+++ b/test/simple/cdata-css/sample-a.txt
@@ -0,0 +1 @@
+hello world
\ No newline at end of file
diff --git a/test/simple/cdata-css/sample-b-expected.txt b/test/simple/cdata-css/sample-b-expected.txt
new file mode 100644
index 0000000..f0cbc90
--- /dev/null
+++ b/test/simple/cdata-css/sample-b-expected.txt
@@ -0,0 +1,3 @@
+/*<![CDATA[*/
+<[[goodbye world]]]]><![CDATA[>
+/*]]>*/
\ No newline at end of file
diff --git a/test/simple/cdata-css/sample-b.txt b/test/simple/cdata-css/sample-b.txt
new file mode 100644
index 0000000..9608cc9
--- /dev/null
+++ b/test/simple/cdata-css/sample-b.txt
@@ -0,0 +1 @@
+<[[goodbye world]]>
\ No newline at end of file
diff --git a/test/simple/cdata-js/sample-a-expected.txt b/test/simple/cdata-js/sample-a-expected.txt
new file mode 100644
index 0000000..4baa5e8
--- /dev/null
+++ b/test/simple/cdata-js/sample-a-expected.txt
@@ -0,0 +1,3 @@
+//<![CDATA[
+hello world
+//]]>
\ No newline at end of file
diff --git a/test/simple/cdata-js/sample-a.txt b/test/simple/cdata-js/sample-a.txt
new file mode 100644
index 0000000..95d09f2
--- /dev/null
+++ b/test/simple/cdata-js/sample-a.txt
@@ -0,0 +1 @@
+hello world
\ No newline at end of file
diff --git a/test/simple/cdata-js/sample-b-expected.txt b/test/simple/cdata-js/sample-b-expected.txt
new file mode 100644
index 0000000..e7f1364
--- /dev/null
+++ b/test/simple/cdata-js/sample-b-expected.txt
@@ -0,0 +1,3 @@
+//<![CDATA[
+<[[goodbye world]]]]><![CDATA[>
+//]]>
\ No newline at end of file
diff --git a/test/simple/cdata-js/sample-b.txt b/test/simple/cdata-js/sample-b.txt
new file mode 100644
index 0000000..9608cc9
--- /dev/null
+++ b/test/simple/cdata-js/sample-b.txt
@@ -0,0 +1 @@
+<[[goodbye world]]>
\ No newline at end of file
diff --git a/test/simple/cdata/sample-a-expected.txt b/test/simple/cdata/sample-a-expected.txt
new file mode 100644
index 0000000..de6de04
--- /dev/null
+++ b/test/simple/cdata/sample-a-expected.txt
@@ -0,0 +1 @@
+<![CDATA[hello world]]>
\ No newline at end of file
diff --git a/test/simple/cdata/sample-a.txt b/test/simple/cdata/sample-a.txt
new file mode 100644
index 0000000..95d09f2
--- /dev/null
+++ b/test/simple/cdata/sample-a.txt
@@ -0,0 +1 @@
+hello world
\ No newline at end of file
diff --git a/test/simple/cdata/sample-b-expected.txt b/test/simple/cdata/sample-b-expected.txt
new file mode 100644
index 0000000..2f8adf1
--- /dev/null
+++ b/test/simple/cdata/sample-b-expected.txt
@@ -0,0 +1 @@
+<![CDATA[<[[goodbye world]]]]><![CDATA[>]]>
\ No newline at end of file
diff --git a/test/simple/cdata/sample-b.txt b/test/simple/cdata/sample-b.txt
new file mode 100644
index 0000000..9608cc9
--- /dev/null
+++ b/test/simple/cdata/sample-b.txt
@@ -0,0 +1 @@
+<[[goodbye world]]>
\ No newline at end of file
diff --git a/test/simple/coffee-script/sample-a-expected.txt b/test/simple/coffee-script/sample-a-expected.txt
new file mode 100644
index 0000000..a65ebe7
--- /dev/null
+++ b/test/simple/coffee-script/sample-a-expected.txt
@@ -0,0 +1,6 @@
+(function() {
+  var n;
+
+  n = 4;
+
+}).call(this);
diff --git a/test/simple/coffee-script/sample-a.txt b/test/simple/coffee-script/sample-a.txt
new file mode 100644
index 0000000..a7c552d
--- /dev/null
+++ b/test/simple/coffee-script/sample-a.txt
@@ -0,0 +1 @@
+n = 4;
\ No newline at end of file
diff --git a/test/simple/coffee-script/sample-b-expected.txt b/test/simple/coffee-script/sample-b-expected.txt
new file mode 100644
index 0000000..a65ebe7
--- /dev/null
+++ b/test/simple/coffee-script/sample-b-expected.txt
@@ -0,0 +1,6 @@
+(function() {
+  var n;
+
+  n = 4;
+
+}).call(this);
diff --git a/test/simple/coffee-script/sample-b.txt b/test/simple/coffee-script/sample-b.txt
new file mode 100644
index 0000000..a7c552d
--- /dev/null
+++ b/test/simple/coffee-script/sample-b.txt
@@ -0,0 +1 @@
+n = 4;
\ No newline at end of file
diff --git a/test/simple/coffeecup/sample-a-expected.txt b/test/simple/coffeecup/sample-a-expected.txt
new file mode 100644
index 0000000..c8be9c2
--- /dev/null
+++ b/test/simple/coffeecup/sample-a-expected.txt
@@ -0,0 +1 @@
+<ul><li>foo</li><li>bar</li></ul>
\ No newline at end of file
diff --git a/test/simple/coffeecup/sample-a.txt b/test/simple/coffeecup/sample-a.txt
new file mode 100644
index 0000000..f369928
--- /dev/null
+++ b/test/simple/coffeecup/sample-a.txt
@@ -0,0 +1,3 @@
+ul ->
+  li 'foo'
+  li 'bar'
\ No newline at end of file
diff --git a/test/simple/coffeecup/sample-b-expected.txt b/test/simple/coffeecup/sample-b-expected.txt
new file mode 100644
index 0000000..8c02a7f
--- /dev/null
+++ b/test/simple/coffeecup/sample-b-expected.txt
@@ -0,0 +1 @@
+<ol><li>foo</li><li>bar</li></ol>
\ No newline at end of file
diff --git a/test/simple/coffeecup/sample-b.txt b/test/simple/coffeecup/sample-b.txt
new file mode 100644
index 0000000..f75d443
--- /dev/null
+++ b/test/simple/coffeecup/sample-b.txt
@@ -0,0 +1,3 @@
+ol ->
+  li 'foo'
+  li 'bar'
\ No newline at end of file
diff --git a/test/simple/cson/sample-a-expected.txt b/test/simple/cson/sample-a-expected.txt
new file mode 100644
index 0000000..500bb12
--- /dev/null
+++ b/test/simple/cson/sample-a-expected.txt
@@ -0,0 +1 @@
+{"abc":["a","b","c"],"a":{"b":"c"}}
\ No newline at end of file
diff --git a/test/simple/cson/sample-a.txt b/test/simple/cson/sample-a.txt
new file mode 100644
index 0000000..11c3d1d
--- /dev/null
+++ b/test/simple/cson/sample-a.txt
@@ -0,0 +1,9 @@
+{
+    abc: [
+        'a'
+        'b'
+        'c'
+    ]
+    a:
+        b: 'c'
+}
\ No newline at end of file
diff --git a/test/simple/cson/sample-b-expected.txt b/test/simple/cson/sample-b-expected.txt
new file mode 100644
index 0000000..63d5fe1
--- /dev/null
+++ b/test/simple/cson/sample-b-expected.txt
@@ -0,0 +1 @@
+{"abc":["a",5,"c"],"a":{"b":"c"}}
\ No newline at end of file
diff --git a/test/simple/cson/sample-b.txt b/test/simple/cson/sample-b.txt
new file mode 100644
index 0000000..101b9f5
--- /dev/null
+++ b/test/simple/cson/sample-b.txt
@@ -0,0 +1,9 @@
+{
+    abc: [
+        'a'
+        5
+        'c'
+    ]
+    a:
+        b: 'c'
+}
\ No newline at end of file
diff --git a/test/simple/dot/sample-a.txt b/test/simple/dot/sample-a.txt
new file mode 100644
index 0000000..e2fc66c
--- /dev/null
+++ b/test/simple/dot/sample-a.txt
@@ -0,0 +1 @@
+<p>{{=it.user.name}}</p>
\ No newline at end of file
diff --git a/test/simple/dot/sample-b.txt b/test/simple/dot/sample-b.txt
new file mode 100644
index 0000000..6ea9cf0
--- /dev/null
+++ b/test/simple/dot/sample-b.txt
@@ -0,0 +1 @@
+<strong>{{=it.user.name}}</strong>
\ No newline at end of file
diff --git a/test/simple/dust/sample-a.txt b/test/simple/dust/sample-a.txt
new file mode 100644
index 0000000..d2f6eeb
--- /dev/null
+++ b/test/simple/dust/sample-a.txt
@@ -0,0 +1 @@
+<p>{user.name}</p>
\ No newline at end of file
diff --git a/test/simple/dust/sample-b.txt b/test/simple/dust/sample-b.txt
new file mode 100644
index 0000000..d6a4bea
--- /dev/null
+++ b/test/simple/dust/sample-b.txt
@@ -0,0 +1 @@
+<strong>{user.name}</strong>
\ No newline at end of file
diff --git a/test/simple/eco/sample-a.txt b/test/simple/eco/sample-a.txt
new file mode 100644
index 0000000..e95657f
--- /dev/null
+++ b/test/simple/eco/sample-a.txt
@@ -0,0 +1 @@
+<p><%= @user.name %></p>
\ No newline at end of file
diff --git a/test/simple/eco/sample-b.txt b/test/simple/eco/sample-b.txt
new file mode 100644
index 0000000..a78ce39
--- /dev/null
+++ b/test/simple/eco/sample-b.txt
@@ -0,0 +1 @@
+<strong><%= @user.name %></strong>
\ No newline at end of file
diff --git a/test/simple/ect/sample-a.txt b/test/simple/ect/sample-a.txt
new file mode 100644
index 0000000..e95657f
--- /dev/null
+++ b/test/simple/ect/sample-a.txt
@@ -0,0 +1 @@
+<p><%= @user.name %></p>
\ No newline at end of file
diff --git a/test/simple/ect/sample-b.txt b/test/simple/ect/sample-b.txt
new file mode 100644
index 0000000..a78ce39
--- /dev/null
+++ b/test/simple/ect/sample-b.txt
@@ -0,0 +1 @@
+<strong><%= @user.name %></strong>
\ No newline at end of file
diff --git a/test/simple/ejs/sample-a.txt b/test/simple/ejs/sample-a.txt
new file mode 100644
index 0000000..b015881
--- /dev/null
+++ b/test/simple/ejs/sample-a.txt
@@ -0,0 +1 @@
+<p><%= user.name %></p>
\ No newline at end of file
diff --git a/test/simple/ejs/sample-b.txt b/test/simple/ejs/sample-b.txt
new file mode 100644
index 0000000..a55afc5
--- /dev/null
+++ b/test/simple/ejs/sample-b.txt
@@ -0,0 +1 @@
+<strong><%= user.name %></strong>
\ No newline at end of file
diff --git a/test/simple/escape-html/sample-a-expected.txt b/test/simple/escape-html/sample-a-expected.txt
new file mode 100644
index 0000000..3b18e51
--- /dev/null
+++ b/test/simple/escape-html/sample-a-expected.txt
@@ -0,0 +1 @@
+hello world
diff --git a/test/simple/escape-html/sample-a.txt b/test/simple/escape-html/sample-a.txt
new file mode 100644
index 0000000..3b18e51
--- /dev/null
+++ b/test/simple/escape-html/sample-a.txt
@@ -0,0 +1 @@
+hello world
diff --git a/test/simple/escape-html/sample-b-expected.txt b/test/simple/escape-html/sample-b-expected.txt
new file mode 100644
index 0000000..b13228e
--- /dev/null
+++ b/test/simple/escape-html/sample-b-expected.txt
@@ -0,0 +1 @@
+<span class="foo" id=&#x27;bar&#x27;>goodbye world</span>
diff --git a/test/simple/escape-html/sample-b.txt b/test/simple/escape-html/sample-b.txt
new file mode 100644
index 0000000..d9d9c6c
--- /dev/null
+++ b/test/simple/escape-html/sample-b.txt
@@ -0,0 +1 @@
+<span class="foo" id='bar'>goodbye world</span>
diff --git a/test/simple/haml-coffee/sample-a.txt b/test/simple/haml-coffee/sample-a.txt
new file mode 100644
index 0000000..c6b8fb8
--- /dev/null
+++ b/test/simple/haml-coffee/sample-a.txt
@@ -0,0 +1 @@
+%p= @user.name
\ No newline at end of file
diff --git a/test/simple/haml-coffee/sample-b.txt b/test/simple/haml-coffee/sample-b.txt
new file mode 100644
index 0000000..d579cbe
--- /dev/null
+++ b/test/simple/haml-coffee/sample-b.txt
@@ -0,0 +1 @@
+%strong= @user.name
\ No newline at end of file
diff --git a/test/simple/haml/sample-a-expected.txt b/test/simple/haml/sample-a-expected.txt
new file mode 100644
index 0000000..a692f8f
--- /dev/null
+++ b/test/simple/haml/sample-a-expected.txt
@@ -0,0 +1,2 @@
+
+<p>bob</p>
\ No newline at end of file
diff --git a/test/simple/haml/sample-a.txt b/test/simple/haml/sample-a.txt
new file mode 100644
index 0000000..166d315
--- /dev/null
+++ b/test/simple/haml/sample-a.txt
@@ -0,0 +1 @@
+%p= user.name
\ No newline at end of file
diff --git a/test/simple/haml/sample-b-expected.txt b/test/simple/haml/sample-b-expected.txt
new file mode 100644
index 0000000..8260b87
--- /dev/null
+++ b/test/simple/haml/sample-b-expected.txt
@@ -0,0 +1,2 @@
+
+<strong>bob</strong>
\ No newline at end of file
diff --git a/test/simple/haml/sample-b.txt b/test/simple/haml/sample-b.txt
new file mode 100644
index 0000000..f64da6e
--- /dev/null
+++ b/test/simple/haml/sample-b.txt
@@ -0,0 +1 @@
+%strong= user.name
\ No newline at end of file
diff --git a/test/simple/handlebars/sample-a.txt b/test/simple/handlebars/sample-a.txt
new file mode 100644
index 0000000..f5b9962
--- /dev/null
+++ b/test/simple/handlebars/sample-a.txt
@@ -0,0 +1 @@
+<p>{{user.name}}</p>
\ No newline at end of file
diff --git a/test/simple/handlebars/sample-b.txt b/test/simple/handlebars/sample-b.txt
new file mode 100644
index 0000000..3dcaa58
--- /dev/null
+++ b/test/simple/handlebars/sample-b.txt
@@ -0,0 +1 @@
+<strong>{{user.name}}</strong>
\ No newline at end of file
diff --git a/test/simple/hogan/sample-a.txt b/test/simple/hogan/sample-a.txt
new file mode 100644
index 0000000..f5b9962
--- /dev/null
+++ b/test/simple/hogan/sample-a.txt
@@ -0,0 +1 @@
+<p>{{user.name}}</p>
\ No newline at end of file
diff --git a/test/simple/hogan/sample-b.txt b/test/simple/hogan/sample-b.txt
new file mode 100644
index 0000000..3dcaa58
--- /dev/null
+++ b/test/simple/hogan/sample-b.txt
@@ -0,0 +1 @@
+<strong>{{user.name}}</strong>
\ No newline at end of file
diff --git a/test/simple/jade/sample-a.txt b/test/simple/jade/sample-a.txt
new file mode 100644
index 0000000..623c665
--- /dev/null
+++ b/test/simple/jade/sample-a.txt
@@ -0,0 +1 @@
+p= user.name
\ No newline at end of file
diff --git a/test/simple/jade/sample-b.txt b/test/simple/jade/sample-b.txt
new file mode 100644
index 0000000..da8875c
--- /dev/null
+++ b/test/simple/jade/sample-b.txt
@@ -0,0 +1 @@
+strong= user.name
\ No newline at end of file
diff --git a/test/simple/jazz/sample-a.txt b/test/simple/jazz/sample-a.txt
new file mode 100644
index 0000000..d2f6eeb
--- /dev/null
+++ b/test/simple/jazz/sample-a.txt
@@ -0,0 +1 @@
+<p>{user.name}</p>
\ No newline at end of file
diff --git a/test/simple/jazz/sample-b.txt b/test/simple/jazz/sample-b.txt
new file mode 100644
index 0000000..d6a4bea
--- /dev/null
+++ b/test/simple/jazz/sample-b.txt
@@ -0,0 +1 @@
+<strong>{user.name}</strong>
\ No newline at end of file
diff --git a/test/simple/jqtpl/sample-a.txt b/test/simple/jqtpl/sample-a.txt
new file mode 100644
index 0000000..13817b6
--- /dev/null
+++ b/test/simple/jqtpl/sample-a.txt
@@ -0,0 +1 @@
+<p>${user.name}</p>
\ No newline at end of file
diff --git a/test/simple/jqtpl/sample-b.txt b/test/simple/jqtpl/sample-b.txt
new file mode 100644
index 0000000..3636556
--- /dev/null
+++ b/test/simple/jqtpl/sample-b.txt
@@ -0,0 +1 @@
+<strong>${user.name}</strong>
\ No newline at end of file
diff --git a/test/simple/just/sample-a.txt b/test/simple/just/sample-a.txt
new file mode 100644
index 0000000..b015881
--- /dev/null
+++ b/test/simple/just/sample-a.txt
@@ -0,0 +1 @@
+<p><%= user.name %></p>
\ No newline at end of file
diff --git a/test/simple/just/sample-b.txt b/test/simple/just/sample-b.txt
new file mode 100644
index 0000000..a55afc5
--- /dev/null
+++ b/test/simple/just/sample-b.txt
@@ -0,0 +1 @@
+<strong><%= user.name %></strong>
\ No newline at end of file
diff --git a/test/simple/less/sample-a-expected.txt b/test/simple/less/sample-a-expected.txt
new file mode 100644
index 0000000..143124d
--- /dev/null
+++ b/test/simple/less/sample-a-expected.txt
@@ -0,0 +1,24 @@
+.variables {
+  width: 14cm;
+}
+.variables {
+  height: 24px;
+  color: #888888;
+  font-family: "Trebuchet MS", Verdana, sans-serif;
+  quotes: "~" "~";
+}
+.redefinition {
+  three: 3;
+}
+.values {
+  font-family: 'Trebuchet', 'Trebuchet', 'Trebuchet';
+  color: #888888 !important;
+  url: url('Trebuchet');
+  multi: something 'A', B, C, 'Trebuchet';
+}
+.variable-names {
+  name: 'hello';
+}
+.alpha {
+  filter: alpha(opacity=42);
+}
diff --git a/test/simple/less/sample-a.txt b/test/simple/less/sample-a.txt
new file mode 100644
index 0000000..a581a7a
--- /dev/null
+++ b/test/simple/less/sample-a.txt
@@ -0,0 +1,50 @@
+ at a: 2;
+ at x: @a * @a;
+ at y: @x + 1;
+ at z: @x * 2 + @y;
+
+.variables {
+  width: @z + 1cm; // 14cm
+}
+
+ at b: @a * 10;
+ at c: #888;
+
+ at fonts: "Trebuchet MS", Verdana, sans-serif;
+ at f: @fonts;
+
+ at quotes: "~" "~";
+ at q: @quotes;
+
+.variables {
+  height: @b + @x + 0px; // 24px
+  color: @c;
+  font-family: @f;
+  quotes: @q;
+}
+
+.redefinition {
+    @var: 4;
+    @var: 2;
+    @var: 3;
+    three: @var;
+}
+
+.values {
+    @a: 'Trebuchet';
+    @multi: 'A', B, C;
+    font-family: @a, @a, @a;
+    color: @c !important;
+    url: url(@a);
+    multi: something @multi, @a;
+}
+
+.variable-names {
+    @var: 'hello';
+    @name: 'var';
+    name: @@name;
+}
+.alpha {
+    @var: 42;
+    filter: alpha(opacity=@var);
+}
\ No newline at end of file
diff --git a/test/simple/less/sample-b-expected.txt b/test/simple/less/sample-b-expected.txt
new file mode 100644
index 0000000..10bc9af
--- /dev/null
+++ b/test/simple/less/sample-b-expected.txt
@@ -0,0 +1,24 @@
+.variables {
+  width: 14cm;
+}
+.variables {
+  height: 24px;
+  color: #888888;
+  font-family: "Trebuchet MS";
+  quotes: "~" "~";
+}
+.redefinition {
+  three: 3;
+}
+.values {
+  font-family: 'Trebuchet', 'Trebuchet', 'Trebuchet';
+  color: #888888 !important;
+  url: url('Trebuchet');
+  multi: something 'A', B, C, 'Trebuchet';
+}
+.variable-names {
+  name: 'hello';
+}
+.alpha {
+  filter: alpha(opacity=42);
+}
diff --git a/test/simple/less/sample-b.txt b/test/simple/less/sample-b.txt
new file mode 100644
index 0000000..d3f5192
--- /dev/null
+++ b/test/simple/less/sample-b.txt
@@ -0,0 +1,50 @@
+ at a: 2;
+ at x: @a * @a;
+ at y: @x + 1;
+ at z: @x * 2 + @y;
+
+.variables {
+  width: @z + 1cm; // 14cm
+}
+
+ at b: @a * 10;
+ at c: #888;
+
+ at fonts: "Trebuchet MS";
+ at f: @fonts;
+
+ at quotes: "~" "~";
+ at q: @quotes;
+
+.variables {
+  height: @b + @x + 0px; // 24px
+  color: @c;
+  font-family: @f;
+  quotes: @q;
+}
+
+.redefinition {
+    @var: 4;
+    @var: 2;
+    @var: 3;
+    three: @var;
+}
+
+.values {
+    @a: 'Trebuchet';
+    @multi: 'A', B, C;
+    font-family: @a, @a, @a;
+    color: @c !important;
+    url: url(@a);
+    multi: something @multi, @a;
+}
+
+.variable-names {
+    @var: 'hello';
+    @name: 'var';
+    name: @@name;
+}
+.alpha {
+    @var: 42;
+    filter: alpha(opacity=@var);
+}
\ No newline at end of file
diff --git a/test/simple/liquor/sample-a.txt b/test/simple/liquor/sample-a.txt
new file mode 100644
index 0000000..04b1781
--- /dev/null
+++ b/test/simple/liquor/sample-a.txt
@@ -0,0 +1 @@
+<p>#{user.name}</p>
\ No newline at end of file
diff --git a/test/simple/liquor/sample-b.txt b/test/simple/liquor/sample-b.txt
new file mode 100644
index 0000000..76eedd8
--- /dev/null
+++ b/test/simple/liquor/sample-b.txt
@@ -0,0 +1 @@
+<strong>#{user.name}</strong>
\ No newline at end of file
diff --git a/test/simple/markdown/sample-a-expected.txt b/test/simple/markdown/sample-a-expected.txt
new file mode 100644
index 0000000..eaa9191
--- /dev/null
+++ b/test/simple/markdown/sample-a-expected.txt
@@ -0,0 +1,6 @@
+<h1 id="heading-1">Heading 1</h1>
+<h2 id="heading-2">Heading 2</h2>
+<ul>
+<li>bullet 1</li>
+<li>bullet 2</li>
+</ul>
diff --git a/test/simple/markdown/sample-a.txt b/test/simple/markdown/sample-a.txt
new file mode 100644
index 0000000..bbd8eb0
--- /dev/null
+++ b/test/simple/markdown/sample-a.txt
@@ -0,0 +1,6 @@
+# Heading 1
+
+## Heading 2
+
+- bullet 1
+- bullet 2
\ No newline at end of file
diff --git a/test/simple/markdown/sample-b-expected.txt b/test/simple/markdown/sample-b-expected.txt
new file mode 100644
index 0000000..9cff74a
--- /dev/null
+++ b/test/simple/markdown/sample-b-expected.txt
@@ -0,0 +1,6 @@
+<h1 id="heading-1">Heading 1</h1>
+<h2 id="heading-2">Heading 2</h2>
+<ol>
+<li>num 1</li>
+<li>num 2</li>
+</ol>
diff --git a/test/simple/markdown/sample-b.txt b/test/simple/markdown/sample-b.txt
new file mode 100644
index 0000000..73f4b83
--- /dev/null
+++ b/test/simple/markdown/sample-b.txt
@@ -0,0 +1,6 @@
+# Heading 1
+
+## Heading 2
+
+1. num 1
+2. num 2
\ No newline at end of file
diff --git a/test/simple/mote/sample-a.txt b/test/simple/mote/sample-a.txt
new file mode 100644
index 0000000..f5b9962
--- /dev/null
+++ b/test/simple/mote/sample-a.txt
@@ -0,0 +1 @@
+<p>{{user.name}}</p>
\ No newline at end of file
diff --git a/test/simple/mote/sample-b.txt b/test/simple/mote/sample-b.txt
new file mode 100644
index 0000000..3dcaa58
--- /dev/null
+++ b/test/simple/mote/sample-b.txt
@@ -0,0 +1 @@
+<strong>{{user.name}}</strong>
\ No newline at end of file
diff --git a/test/simple/mustache/sample-a.txt b/test/simple/mustache/sample-a.txt
new file mode 100644
index 0000000..c7270fb
--- /dev/null
+++ b/test/simple/mustache/sample-a.txt
@@ -0,0 +1 @@
+<p>{{#user}}{{name}}{{/user}}</p>
\ No newline at end of file
diff --git a/test/simple/mustache/sample-b.txt b/test/simple/mustache/sample-b.txt
new file mode 100644
index 0000000..90982ae
--- /dev/null
+++ b/test/simple/mustache/sample-b.txt
@@ -0,0 +1 @@
+<strong>{{#user}}{{name}}{{/user}}</strong>
\ No newline at end of file
diff --git a/test/simple/plates/sample-a-expected.txt b/test/simple/plates/sample-a-expected.txt
new file mode 100644
index 0000000..25f2db2
--- /dev/null
+++ b/test/simple/plates/sample-a-expected.txt
@@ -0,0 +1 @@
+<div id="user"><p id="name">bob</p></div>
\ No newline at end of file
diff --git a/test/simple/plates/sample-a.txt b/test/simple/plates/sample-a.txt
new file mode 100644
index 0000000..4efa161
--- /dev/null
+++ b/test/simple/plates/sample-a.txt
@@ -0,0 +1 @@
+<div id="user"><p id="name"></p></div>
\ No newline at end of file
diff --git a/test/simple/plates/sample-b-expected.txt b/test/simple/plates/sample-b-expected.txt
new file mode 100644
index 0000000..d6969d5
--- /dev/null
+++ b/test/simple/plates/sample-b-expected.txt
@@ -0,0 +1 @@
+<div id="user"><strong id="name">bob</strong></div>
\ No newline at end of file
diff --git a/test/simple/plates/sample-b.txt b/test/simple/plates/sample-b.txt
new file mode 100644
index 0000000..0eb6deb
--- /dev/null
+++ b/test/simple/plates/sample-b.txt
@@ -0,0 +1 @@
+<div id="user"><strong id="name"></strong></div>
\ No newline at end of file
diff --git a/test/simple/qejs/sample-a.txt b/test/simple/qejs/sample-a.txt
new file mode 100644
index 0000000..b015881
--- /dev/null
+++ b/test/simple/qejs/sample-a.txt
@@ -0,0 +1 @@
+<p><%= user.name %></p>
\ No newline at end of file
diff --git a/test/simple/qejs/sample-b.txt b/test/simple/qejs/sample-b.txt
new file mode 100644
index 0000000..a55afc5
--- /dev/null
+++ b/test/simple/qejs/sample-b.txt
@@ -0,0 +1 @@
+<strong><%= user.name %></strong>
\ No newline at end of file
diff --git a/test/simple/sass/sample-a-expected.txt b/test/simple/sass/sample-a-expected.txt
new file mode 100644
index 0000000..6ddc778
--- /dev/null
+++ b/test/simple/sass/sample-a-expected.txt
@@ -0,0 +1,8 @@
+table {
+  border: none;}
+table tr {
+  background: #fff;}
+table tr {
+  font-size: 15px;}
+table tr:odd {
+  background: #000;}
diff --git a/test/simple/sass/sample-a.txt b/test/simple/sass/sample-a.txt
new file mode 100644
index 0000000..a27a945
--- /dev/null
+++ b/test/simple/sass/sample-a.txt
@@ -0,0 +1,11 @@
++large
+  :font-size 15px
++striped
+  tr
+    :background #fff
+    +large
+    &:odd
+      :background #000
+table
+  +striped
+  :border none
\ No newline at end of file
diff --git a/test/simple/sass/sample-b-expected.txt b/test/simple/sass/sample-b-expected.txt
new file mode 100644
index 0000000..603a155
--- /dev/null
+++ b/test/simple/sass/sample-b-expected.txt
@@ -0,0 +1,8 @@
+table {
+  border: none;}
+table tr {
+  background: #000;}
+table tr {
+  font-size: 15px;}
+table tr:odd {
+  background: #fff;}
diff --git a/test/simple/sass/sample-b.txt b/test/simple/sass/sample-b.txt
new file mode 100644
index 0000000..0392bd6
--- /dev/null
+++ b/test/simple/sass/sample-b.txt
@@ -0,0 +1,11 @@
++large
+  :font-size 15px
++striped
+  tr
+    :background #000
+    +large
+    &:odd
+      :background #fff
+table
+  +striped
+  :border none
\ No newline at end of file
diff --git a/test/simple/stylus/sample-a-expected.txt b/test/simple/stylus/sample-a-expected.txt
new file mode 100644
index 0000000..f686c1c
--- /dev/null
+++ b/test/simple/stylus/sample-a-expected.txt
@@ -0,0 +1,8 @@
+body {
+  font: 12px Helvetica, Arial, sans-serif;
+}
+a.button {
+  -webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  border-radius: 5px;
+}
diff --git a/test/simple/stylus/sample-a.txt b/test/simple/stylus/sample-a.txt
new file mode 100644
index 0000000..f2b7d94
--- /dev/null
+++ b/test/simple/stylus/sample-a.txt
@@ -0,0 +1,10 @@
+border-radius()
+  -webkit-border-radius arguments
+  -moz-border-radius arguments
+  border-radius arguments
+  
+body
+  font 12px Helvetica, Arial, sans-serif
+  
+a.button
+  border-radius(5px)
\ No newline at end of file
diff --git a/test/simple/stylus/sample-b-expected.txt b/test/simple/stylus/sample-b-expected.txt
new file mode 100644
index 0000000..11f10bf
--- /dev/null
+++ b/test/simple/stylus/sample-b-expected.txt
@@ -0,0 +1,8 @@
+body {
+  font: 20px Helvetica, Arial, sans-serif;
+}
+a.button {
+  -webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  border-radius: 5px;
+}
diff --git a/test/simple/stylus/sample-b.txt b/test/simple/stylus/sample-b.txt
new file mode 100644
index 0000000..a2d03c2
--- /dev/null
+++ b/test/simple/stylus/sample-b.txt
@@ -0,0 +1,10 @@
+border-radius()
+  -webkit-border-radius arguments
+  -moz-border-radius arguments
+  border-radius arguments
+  
+body
+  font 20px Helvetica, Arial, sans-serif
+  
+a.button
+  border-radius(5px)
\ No newline at end of file
diff --git a/test/simple/swig/sample-a.txt b/test/simple/swig/sample-a.txt
new file mode 100644
index 0000000..f5b9962
--- /dev/null
+++ b/test/simple/swig/sample-a.txt
@@ -0,0 +1 @@
+<p>{{user.name}}</p>
\ No newline at end of file
diff --git a/test/simple/swig/sample-b.txt b/test/simple/swig/sample-b.txt
new file mode 100644
index 0000000..3dcaa58
--- /dev/null
+++ b/test/simple/swig/sample-b.txt
@@ -0,0 +1 @@
+<strong>{{user.name}}</strong>
\ No newline at end of file
diff --git a/test/simple/templayed/sample-a.txt b/test/simple/templayed/sample-a.txt
new file mode 100644
index 0000000..f5b9962
--- /dev/null
+++ b/test/simple/templayed/sample-a.txt
@@ -0,0 +1 @@
+<p>{{user.name}}</p>
\ No newline at end of file
diff --git a/test/simple/templayed/sample-b.txt b/test/simple/templayed/sample-b.txt
new file mode 100644
index 0000000..3dcaa58
--- /dev/null
+++ b/test/simple/templayed/sample-b.txt
@@ -0,0 +1 @@
+<strong>{{user.name}}</strong>
\ No newline at end of file
diff --git a/test/simple/toffee/sample-a.txt b/test/simple/toffee/sample-a.txt
new file mode 100644
index 0000000..04b1781
--- /dev/null
+++ b/test/simple/toffee/sample-a.txt
@@ -0,0 +1 @@
+<p>#{user.name}</p>
\ No newline at end of file
diff --git a/test/simple/toffee/sample-b.txt b/test/simple/toffee/sample-b.txt
new file mode 100644
index 0000000..76eedd8
--- /dev/null
+++ b/test/simple/toffee/sample-b.txt
@@ -0,0 +1 @@
+<strong>#{user.name}</strong>
\ No newline at end of file
diff --git a/test/simple/uglify-css/sample-a-expected.txt b/test/simple/uglify-css/sample-a-expected.txt
new file mode 100644
index 0000000..bf80f1e
--- /dev/null
+++ b/test/simple/uglify-css/sample-a-expected.txt
@@ -0,0 +1 @@
+tobi{name:"tobi"}
\ No newline at end of file
diff --git a/test/simple/uglify-css/sample-a.txt b/test/simple/uglify-css/sample-a.txt
new file mode 100644
index 0000000..bac0d3f
--- /dev/null
+++ b/test/simple/uglify-css/sample-a.txt
@@ -0,0 +1,3 @@
+tobi {
+  name: "tobi"
+}
\ No newline at end of file
diff --git a/test/simple/uglify-css/sample-b-expected.txt b/test/simple/uglify-css/sample-b-expected.txt
new file mode 100644
index 0000000..01859af
--- /dev/null
+++ b/test/simple/uglify-css/sample-b-expected.txt
@@ -0,0 +1 @@
+tobi{name:"bob"}
\ No newline at end of file
diff --git a/test/simple/uglify-css/sample-b.txt b/test/simple/uglify-css/sample-b.txt
new file mode 100644
index 0000000..e55a457
--- /dev/null
+++ b/test/simple/uglify-css/sample-b.txt
@@ -0,0 +1,3 @@
+tobi {
+  name: "bob"
+}
\ No newline at end of file
diff --git a/test/simple/uglify-json/sample-a-expected.txt b/test/simple/uglify-json/sample-a-expected.txt
new file mode 100644
index 0000000..9f5dd4e
--- /dev/null
+++ b/test/simple/uglify-json/sample-a-expected.txt
@@ -0,0 +1 @@
+{"foo":"bar"}
\ No newline at end of file
diff --git a/test/simple/uglify-json/sample-a.txt b/test/simple/uglify-json/sample-a.txt
new file mode 100644
index 0000000..b42f309
--- /dev/null
+++ b/test/simple/uglify-json/sample-a.txt
@@ -0,0 +1,3 @@
+{
+  "foo": "bar"
+}
\ No newline at end of file
diff --git a/test/simple/uglify-json/sample-b-expected.txt b/test/simple/uglify-json/sample-b-expected.txt
new file mode 100644
index 0000000..3a26a2e
--- /dev/null
+++ b/test/simple/uglify-json/sample-b-expected.txt
@@ -0,0 +1 @@
+[1,2,3]
\ No newline at end of file
diff --git a/test/simple/uglify-json/sample-b.txt b/test/simple/uglify-json/sample-b.txt
new file mode 100644
index 0000000..d930309
--- /dev/null
+++ b/test/simple/uglify-json/sample-b.txt
@@ -0,0 +1,5 @@
+[
+  1,
+  2,
+  3
+]
\ No newline at end of file
diff --git a/test/simple/underscore/sample-a.txt b/test/simple/underscore/sample-a.txt
new file mode 100644
index 0000000..a244072
--- /dev/null
+++ b/test/simple/underscore/sample-a.txt
@@ -0,0 +1 @@
+<p><%- user.name %></p>
\ No newline at end of file
diff --git a/test/simple/underscore/sample-b.txt b/test/simple/underscore/sample-b.txt
new file mode 100644
index 0000000..0e320e4
--- /dev/null
+++ b/test/simple/underscore/sample-b.txt
@@ -0,0 +1 @@
+<strong><%- user.name %></strong>
\ No newline at end of file
diff --git a/test/simple/verbatim/sample-a-expected.txt b/test/simple/verbatim/sample-a-expected.txt
new file mode 100644
index 0000000..3b18e51
--- /dev/null
+++ b/test/simple/verbatim/sample-a-expected.txt
@@ -0,0 +1 @@
+hello world
diff --git a/test/simple/verbatim/sample-a.txt b/test/simple/verbatim/sample-a.txt
new file mode 100644
index 0000000..3b18e51
--- /dev/null
+++ b/test/simple/verbatim/sample-a.txt
@@ -0,0 +1 @@
+hello world
diff --git a/test/simple/verbatim/sample-b-expected.txt b/test/simple/verbatim/sample-b-expected.txt
new file mode 100644
index 0000000..eeee2af
--- /dev/null
+++ b/test/simple/verbatim/sample-b-expected.txt
@@ -0,0 +1 @@
+goodbye world
diff --git a/test/simple/verbatim/sample-b.txt b/test/simple/verbatim/sample-b.txt
new file mode 100644
index 0000000..eeee2af
--- /dev/null
+++ b/test/simple/verbatim/sample-b.txt
@@ -0,0 +1 @@
+goodbye world
diff --git a/test/simple/walrus/sample-a.txt b/test/simple/walrus/sample-a.txt
new file mode 100644
index 0000000..ba27a12
--- /dev/null
+++ b/test/simple/walrus/sample-a.txt
@@ -0,0 +1 @@
+<p>{{ user.name }}</p>
\ No newline at end of file
diff --git a/test/simple/walrus/sample-b.txt b/test/simple/walrus/sample-b.txt
new file mode 100644
index 0000000..be635ff
--- /dev/null
+++ b/test/simple/walrus/sample-b.txt
@@ -0,0 +1 @@
+<strong>{{ user.name }}</strong>
\ No newline at end of file
diff --git a/test/simple/whiskers/sample-a.txt b/test/simple/whiskers/sample-a.txt
new file mode 100644
index 0000000..d2f6eeb
--- /dev/null
+++ b/test/simple/whiskers/sample-a.txt
@@ -0,0 +1 @@
+<p>{user.name}</p>
\ No newline at end of file
diff --git a/test/simple/whiskers/sample-b.txt b/test/simple/whiskers/sample-b.txt
new file mode 100644
index 0000000..d6a4bea
--- /dev/null
+++ b/test/simple/whiskers/sample-b.txt
@@ -0,0 +1 @@
+<strong>{user.name}</strong>
\ No newline at end of file
diff --git a/test/test.js b/test/test.js
new file mode 100644
index 0000000..5fd4e90
--- /dev/null
+++ b/test/test.js
@@ -0,0 +1,108 @@
+var transformers = require('../');
+var fs = require('fs');
+var path = require('path');
+var expect = require('expect.js');
+
+fs.readdirSync(path.join(__dirname, 'simple'))
+  .forEach(function (transformer) {
+    if (!transformers[transformer]) {
+      throw new Error(transformer + ' appears to be undefined.');
+    }
+    transformer = transformers[transformer];
+    function locate(name) {
+      return path.join(__dirname, 'simple', transformer.name, name + '.txt');
+    }
+    function read(name) {
+      try {
+        return fs.readFileSync(locate(name)).toString();
+      } catch (ex) {
+        return null;
+      }
+    }
+    describe(transformer.name, function () {
+      var sampleA = read('sample-a');
+      var sampleAExpected = (read('sample-a-expected') || '<p>bob</p>').replace(/\r/g, '');
+      var sampleB = read('sample-b');
+      var sampleBExpected = (read('sample-b-expected') || '<strong>bob</strong>').replace(/\r/g, '');
+      if (transformer.sync) describe('syncronous operation', testSyncronousOperation);
+      else describe.skip('syncronous operation', testSyncronousOperation);
+      function testSyncronousOperation() {
+        it('works from a string', function () {
+          expect(transformer.renderSync(sampleA, {user: {name: 'bob'}})).to.be(sampleAExpected);
+          expect(transformer.renderSync(sampleB, {user: {name: 'bob'}})).to.be(sampleBExpected);
+        });
+        it('works from a file', function () {
+          expect(transformer.renderFileSync(locate('sample-a'), {user: {name: 'bob'}})).to.be(sampleAExpected);
+          expect(transformer.renderFileSync(locate('sample-b'), {user: {name: 'bob'}})).to.be(sampleBExpected);
+        });
+      }
+      describe('asyncronous operation', function () {
+        it('works from a string A', function (done) {
+          transformer.render(sampleA, {user: {name: 'bob'}}, function (err, res) {
+            if (err) return done(err);
+            expect(res).to.be(sampleAExpected);
+            done();
+          });
+        });
+        it('works from a string B', function (done) {
+          transformer.render(sampleB, {user: {name: 'bob'}}, function (err, res) {
+            if (err) return done(err);
+            expect(res).to.be(sampleBExpected);
+            done();
+          });
+        });
+        it('works from a file A', function (done) {
+          transformer.renderFile(locate('sample-a'), {user: {name: 'bob'}}, function (err, res) {
+            if (err) return done(err);
+            expect(res).to.be(sampleAExpected);
+            done();
+          });
+        });
+        it('works from a file B', function (done) {
+          transformer.renderFile(locate('sample-b'), {user: {name: 'bob'}}, function (err, res) {
+            if (err) return done(err);
+            expect(res).to.be(sampleBExpected);
+            done();
+          });
+        });
+      })
+    });
+  });
+
+
+
+    function read(name) {
+      try {
+        return fs.readFileSync(locate(name)).toString();
+      } catch (ex) {
+        return null;
+      }
+    }
+
+
+describe('uglify-js', function () {
+  var str = fs.readFileSync(path.join(__dirname, 'fixtures', 'uglify-js', 'script.js')).toString();
+  it('minifies files', function () {
+    var res = transformers['uglify-js'].renderSync(str, {});
+    expect(res.length).to.be.lessThan(82);
+    expect(require('vm').runInNewContext(res)).to.be('Hello Forbes Lindesay!');
+  });
+  it('beautifies files with {mangle: false, compress: false, output: {beautify: true}}', function () {
+    var res = transformers['uglify-js'].renderSync(str, {mangle: false, compress: false, output: {beautify: true}});
+    expect(res).to.be('(function(name) {\n    function hello(world) {\n        return "Hello " + world + "!";\n    }\n    return hello(name);\n})("Forbes Lindesay");');
+    expect(require('vm').runInNewContext(res)).to.be('Hello Forbes Lindesay!');
+  });
+});
+
+describe('stylus', function () {
+  var p = path.join(__dirname, 'fixtures', 'stylus', 'sample.styl');
+  var expected = path.join(__dirname, 'fixtures', 'stylus', 'expected.css');
+
+  it('can define custom variables', function (done){
+    transformers['stylus'].renderFile(p, { define: { custom_color: 'red', foo: 'bar' } }, function (err, res) {
+      expect(res.replace(/\r/g, '')).to.be(fs.readFileSync(expected, 'utf8').replace(/\r/g, ''))
+      done();
+    });
+  });
+
+});
diff --git a/test/update-package.js b/test/update-package.js
new file mode 100644
index 0000000..0e20cc8
--- /dev/null
+++ b/test/update-package.js
@@ -0,0 +1,13 @@
+var transformers = require('../');
+var pack = require('../package');
+Object.keys(transformers)
+  .forEach(function (transformer) {
+    transformers[transformer].engines
+      .forEach(function (engine) {
+        if (engine != '.' && !pack.devDependencies[engine]) {
+          pack.devDependencies[engine] = '*';
+        }
+      });
+  });
+require('fs').writeFileSync(require('path').join(__dirname, '..', 'package.json'),
+  JSON.stringify(pack, null, 2));
\ No newline at end of file

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-transformers.git



More information about the Pkg-javascript-commits mailing list