/* * Copyright 2011 <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ocpsoft.rewrite.transform.less; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.nio.charset.Charset; import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; import org.ocpsoft.common.util.Streams; import org.ocpsoft.rewrite.servlet.http.event.HttpServletRewrite; import org.ocpsoft.rewrite.transform.StringTransformer; import org.ocpsoft.rewrite.transform.Transformer; /** * A {@link Transformer} that compiles LESS files into CSS. This implementation is based on Mozilla Rhino and LESS * 1.3.0. * * @author Christian Kaltepoth */ public class Less extends StringTransformer { private final String baseScript; /** * Create a {@link Transformer} that compiles LESS files into CSS. */ public static Less compiler() { return new Less(); } private Less() { StringBuilder scriptBuilder = new StringBuilder(); scriptBuilder.append("function print(s) {}"); // required by env.rhino scriptBuilder.append(getClasspathResourceAsString("org/ocpsoft/rewrite/transform/js/" + "env.rhino.1.2.js")); scriptBuilder.append(getClasspathResourceAsString("org/ocpsoft/rewrite/transform/js/" + "less-1.3.0.min.js")); scriptBuilder.append(getClasspathResourceAsString("org/ocpsoft/rewrite/transform/js/" + "api.js")); baseScript = scriptBuilder.toString(); } @Override public String transform(HttpServletRewrite event, String less) { Context context = Context.enter(); try { context.setOptimizationLevel(-1); context.setLanguageVersion(Context.VERSION_1_6); Scriptable scope = context.initStandardObjects(); String script = new StringBuilder(baseScript) .append("lessToCss('") .append(escape(less)) .append("');") .toString(); Object result = context.evaluateString(scope, script, this.getClass().getSimpleName(), 1, null); if (result != null) { return result.toString(); } } finally { Context.exit(); } return null; } private static String getClasspathResourceAsString(String resource) { InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource); if (input == null) { throw new IllegalStateException("Could not find resource on the classpath: " + resource); } ByteArrayOutputStream output = new ByteArrayOutputStream(); Streams.copy(input, output); return new String(output.toByteArray(), Charset.forName("UTF-8")); } private String escape(String s) { return s.replace("\r", "").replace("\n", "\\n"); } }