/*
* Copyright 2010.
*/
package ro.isdc.wro.extensions.processor.support.coffeescript;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import org.mozilla.javascript.ScriptableObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ro.isdc.wro.extensions.locator.WebjarUriLocator;
import ro.isdc.wro.extensions.processor.support.linter.LinterException;
import ro.isdc.wro.extensions.script.RhinoScriptBuilder;
import ro.isdc.wro.util.WroUtil;
/**
* CoffeeScript is a little language that compiles into JavaScript. Underneath all of those embarrassing braces and
* semicolons, JavaScript has always had a gorgeous object model at its heart. CoffeeScript is an attempt to expose the
* good parts of JavaScript in a simple way.
* <p/>
* This processor loads coffee-script library from the webjar.
*
* @author Alex Objelean
* @since 1.3.6
*/
public class CoffeeScript {
private static final Logger LOG = LoggerFactory.getLogger(CoffeeScript.class);
private static final String DEFAULT_COFFE_SCRIPT = "coffee-script.js";
private String[] options;
private ScriptableObject scope;
private WebjarUriLocator webjarLocator;
/**
* Initialize script builder for evaluation.
*/
private RhinoScriptBuilder initScriptBuilder() {
try {
RhinoScriptBuilder builder = null;
if (scope == null) {
builder = RhinoScriptBuilder.newChain().evaluateChain(getCoffeeScriptAsStream(), DEFAULT_COFFE_SCRIPT);
scope = builder.getScope();
} else {
builder = RhinoScriptBuilder.newChain(scope);
}
return builder;
} catch (final IOException ex) {
throw new IllegalStateException("Failed reading init script", ex);
}
}
/**
* Override this method to use a different version of CoffeeScript. This method is useful for upgrading coffeeScript
* processor independently of wro4j.
*
* @return The stream of the CoffeeScript.
*/
protected InputStream getCoffeeScriptAsStream() throws IOException {
return getWebjarLocator().locate(WebjarUriLocator.createUri("coffee-script.min.js"));
}
/**
* @return {@link WebjarUriLocator} instance to retrieve webjars.
*/
private WebjarUriLocator getWebjarLocator() {
if (webjarLocator == null) {
webjarLocator = new WebjarUriLocator();
}
return webjarLocator;
}
/**
* Validates a js using jsHint and throws {@link LinterException} if the js is invalid. If no exception is thrown, the
* js is valid.
*
* @param data
* js content to process.
*/
public String compile(final String data) {
final RhinoScriptBuilder builder = initScriptBuilder();
final String compileScript = String.format("CoffeeScript.compile(%s, %s);", WroUtil.toJSMultiLineString(data),
buildOptions());
return (String) builder.evaluate(compileScript, "CoffeeScript.compile");
}
/**
* @return A javascript representation of the options. The result is a json object.
*/
private String buildOptions() {
final StringBuffer sb = new StringBuffer("{");
if (options != null) {
for (int i = 0; i < options.length; i++) {
sb.append(options[i]).append(": true");
if (i < options.length - 1) {
sb.append(",");
}
}
}
sb.append("}");
return sb.toString();
}
/**
* @param options
* the options to set
*/
public CoffeeScript setOptions(final String... options) {
this.options = options == null ? new String[] {} : options;
LOG.debug("setOptions: {}", Arrays.asList(this.options));
return this;
}
}