juzu.plugin.less.impl.LessMetaModelPlugin Maven / Gradle / Ivy
/*
* Copyright 2013 eXo Platform SAS
*
* 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 juzu.plugin.less.impl;
import juzu.impl.common.Name;
import juzu.impl.plugin.module.metamodel.ModuleMetaModel;
import juzu.impl.plugin.module.metamodel.ModuleMetaModelPlugin;
import juzu.impl.metamodel.AnnotationKey;
import juzu.impl.metamodel.AnnotationState;
import juzu.impl.compiler.BaseProcessor;
import juzu.impl.compiler.Message;
import juzu.impl.compiler.ProcessingException;
import juzu.impl.compiler.ElementHandle;
import juzu.impl.compiler.MessageCode;
import juzu.impl.compiler.ProcessingContext;
import juzu.impl.common.Logger;
import juzu.impl.common.Path;
import juzu.impl.common.Tools;
import juzu.plugin.less.Less;
import juzu.plugin.less.impl.lesser.Compilation;
import juzu.plugin.less.impl.lesser.Failure;
import juzu.plugin.less.impl.lesser.JSContext;
import juzu.plugin.less.impl.lesser.LessError;
import juzu.plugin.less.impl.lesser.Lesser;
import juzu.plugin.less.impl.lesser.Result;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.PackageElement;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** @author Julien Viet */
public class LessMetaModelPlugin extends ModuleMetaModelPlugin {
/** . */
public static final MessageCode COMPILATION_ERROR = new MessageCode(
"LESS_COMPILATION_ERROR",
"%1$s in %2$s on line %3$s, column %4$s:\n%5$s");
/** . */
public static final MessageCode MALFORMED_PATH = new MessageCode("LESS_MALFORMED_PATH", "The resource path %1$s is malformed");
/** . */
static final Logger log = BaseProcessor.getLogger(LessMetaModelPlugin.class);
/** . */
private HashMap annotations;
public LessMetaModelPlugin() {
super("less");
}
@Override
public void init(ModuleMetaModel metaModel) {
annotations = new HashMap();
}
@Override
public Set> init(ProcessingContext env) {
return Collections.>singleton(Less.class);
}
@Override
public void processAnnotationAdded(ModuleMetaModel metaModel, AnnotationKey key, AnnotationState added) {
Name pkg = key.getElement().getPackageName();
log.info("Adding less annotation for package " + pkg);
annotations.put(pkg, added);
}
@Override
public void processAnnotationRemoved(ModuleMetaModel metaModel, AnnotationKey key, AnnotationState removed) {
Name pkg = key.getElement().getPackageName();
log.info("Removing less annotation for package " + pkg);
annotations.remove(pkg);
}
@Override
public void postActivate(ModuleMetaModel metaModel) {
annotations = new HashMap();
}
@Override
public void prePassivate(ModuleMetaModel metaModel) {
// First clear annotation map
HashMap clone = annotations;
annotations = null;
//
for (Map.Entry entry : clone.entrySet()) {
AnnotationState annotation = entry.getValue();
Name pkg = entry.getKey();
ProcessingContext env = metaModel.processingContext;
ElementHandle.Package pkgHandle = ElementHandle.Package.create(pkg);
PackageElement pkgElt = env.get(pkgHandle);
Boolean minify = (Boolean)annotation.get("minify");
List resources = (List)annotation.get("value");
// WARNING THIS IS NOT CORRECT BUT WORK FOR NOW
AnnotationMirror annotationMirror = Tools.getAnnotation(pkgElt, Less.class.getName());
//
log.info("Handling less annotation for package " + pkg + ": minify=" + minify + " resources=" + resources);
//
if (resources != null && resources.size() > 0) {
// For now we use the hardcoded assets package
Name assetPkg = pkg.append("assets");
//
CompilerLessContext clc = new CompilerLessContext(env, pkgHandle, assetPkg);
//
for (String resource : resources) {
log.info("Processing declared resource " + resource);
//
Path path;
try {
path = Path.parse(resource);
}
catch (IllegalArgumentException e) {
throw MALFORMED_PATH.failure(pkgElt, annotationMirror, resource).initCause(e);
}
//
Path.Absolute to = assetPkg.resolve(path.as("css"));
log.info("Resource " + resource + " destination resolved to " + to);
//
Lesser lesser;
Result result;
try {
lesser = new Lesser(JSContext.create());
result = lesser.compile(clc, resource, Boolean.TRUE.equals(minify));
}
catch (Exception e) {
log.info("Unexpected exception", e);
throw new UnsupportedOperationException(e);
}
//
if (result instanceof Compilation) {
try {
log.info("Resource " + resource + " compiled about to write on disk as " + to);
Compilation compilation = (Compilation)result;
FileObject fo = env.createResource(StandardLocation.CLASS_OUTPUT, to);
Writer writer = fo.openWriter();
try {
writer.write(compilation.getValue());
}
finally {
Tools.safeClose(writer);
}
}
catch (IOException e) {
log.info("Resource " + to + " could not be written on disk", e);
}
}
else {
Failure failure = (Failure)result;
LinkedList errors = failure.getErrors();
ArrayList messages = new ArrayList(errors.size());
StringBuilder sb = new StringBuilder();
for (LessError error : errors) {
String text = error.message != null ? error.message : "There is an error in your .less file";
int index = error.line - (error.extract.length - 1) / 2;
for (String line : error.extract) {
sb.append("[").append(index).append("]");
sb.append(index == error.line ? " -> " : " ");
sb.append(line).append("\n");
index++;
}
Message msg = new Message(COMPILATION_ERROR,
text,
error.src,
error.line,
error.column + 1,
sb);
log.info(msg.toDisplayString());
messages.add(msg);
}
throw new ProcessingException(pkgElt, annotationMirror, messages);
}
}
}
}
}
}