All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.anyplace.web.JavascriptProcessorMojo Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2013 Davide Imbriaco
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see .
 *
 */
package it.anyplace.web;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;
import com.google.javascript.jscomp.CompilerOptions;
import com.google.javascript.jscomp.SourceFile;
import com.google.javascript.jscomp.Compiler;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;

import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.StringReader;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.maven.plugin.logging.Log;
import org.yaml.snakeyaml.Yaml;

/**
 */
@Mojo(name = "javascript", defaultPhase = LifecyclePhase.PACKAGE)
public class JavascriptProcessorMojo extends AbstractMojo {

    private final Log logger = getLog();

    @Parameter(required = true, property = "sourceJsDirectory", defaultValue = "${project.basedir}/src/main/javascript")
    private File sourceJsDirectory;

    @Parameter(required = true, property = "targetJsDirectory", defaultValue = "${project.build.directory}/${project.build.finalName}/js")
    private File targetJsDirectory;

    @Parameter(property = "defaultPrefix", defaultValue = "")
    private String defaultPrefix;

    @Parameter(property = "compressJs", defaultValue = "false")
    private boolean compressJs;

    @Parameter(property = "validateJson", defaultValue = "true")
    private boolean validateJson;

    public void execute() throws MojoExecutionException {
        try {
            logger.info("executing a-web js processor");
            targetJsDirectory.mkdirs();
            for (File directory : Iterables.concat(Collections.singleton(sourceJsDirectory), Arrays.asList(sourceJsDirectory.listFiles(new FileFilter() {

                public boolean accept(File file) {
                    return file.isDirectory();
                }
            })))) {
                logger.debug("processing js dir = " + directory);
                Collection files = FileUtils.listFiles(directory, TrueFileFilter.INSTANCE, directory.equals(sourceJsDirectory) ? null : TrueFileFilter.INSTANCE);
                if (files.isEmpty()) {
                    continue;
                }
                final Set includedFilesAsCanPath = getIncludedFilesAsCanPath(files);
                files = Lists.newArrayList(Iterables.filter(files, new Predicate() {

                    public boolean apply(File input) {
                        try {
                            return !includedFilesAsCanPath.contains(input.getCanonicalPath());
                        } catch (IOException ex) {
                            throw new RuntimeException(ex);
                        }
                    }
                }));
                Multimap filesByPrefix = Multimaps.index(files, new Function() {

                    public String apply(File file) {
                        return file.getName().replaceFirst("^([a-z0-9-]*)(_.*)?[.](js)$", "$1");
                    }
                });
                String prefix;
                if (filesByPrefix.keySet().size() == 1 && !filesByPrefix.keys().iterator().next().isEmpty()) {
                    prefix = filesByPrefix.keys().iterator().next().replaceFirst("_$", "");
                } else if (directory.equals(sourceJsDirectory)) {
                    prefix = defaultPrefix;
                } else {
                    prefix = defaultPrefix + "-" + directory.getName();
                }
                prefix = prefix.replaceFirst("[.].*$", "");
                processJsFiles(prefix, files);
            }

            logger.info("executed a-web js processor");
        } catch (IOException ex) {
            throw new MojoExecutionException("IO error", ex);
        }
    }
    private final Pattern pattern = Pattern.compile("anyplacetools.importFile\\(['\"]([^'\"]+)['\"]\\)", Pattern.DOTALL);
    private final Yaml yaml = new Yaml();
    private final Gson gson = new GsonBuilder().setPrettyPrinting().create();

    private Set getIncludedFilesAsCanPath(Iterable files) throws IOException {
        Set res = Sets.newHashSet();
        for (File file : files) {
            Matcher matcher = pattern.matcher(FileUtils.readFileToString(file));
            while (matcher.find()) {
                String relativePath = Strings.emptyToNull(matcher.group(1));
                Preconditions.checkNotNull(relativePath);
                res.add(new File(file.getParentFile(), relativePath).getCanonicalPath());
            }
        }
        return res;
    }

    private static boolean isJson(File file) {
        return file.getName().endsWith(".json");
    }

    private static boolean isYaml(File file) {
        return file.getName().endsWith(".yml") || file.getName().endsWith(".yaml");
    }

    private String readFile(File file) throws IOException {
        String data = FileUtils.readFileToString(file);
        {
            Matcher matcher = pattern.matcher(data);
            StringBuffer stringBuffer = new StringBuffer();
            while (matcher.find()) {
                String relativePath = Strings.emptyToNull(matcher.group(1));
                Preconditions.checkNotNull(relativePath);
                File importFile = new File(file.getParentFile(), relativePath);
                Preconditions.checkArgument(importFile.exists() && importFile.canRead(), "file not fount = %s", importFile);
                logger.info("importing " + importFile + " from " + file);
                String importData = readFile(importFile);
                matcher.appendReplacement(stringBuffer, importData.replace("\\", "\\\\").replace("$", "\\$"));
            }
            matcher.appendTail(stringBuffer);
            data = stringBuffer.toString();
        }
        if (isJson(file) && validateJson) {
            logger.debug("validating json");
            JsonParser jsonParser = new JsonParser();
            jsonParser.parse(new StringReader(data));
        } else if (isYaml(file)) {
            Object yamlBean = yaml.load(data);
            data = gson.toJson(yamlBean);
        }
        return data;
    }

    private void processJsFiles(String prefix, Collection files) throws IOException {
        logger.info("processing js = " + prefix);
        files = Ordering.usingToString().sortedCopy(files);
        String targetFileName = prefix + ".js";
        File destFile = new File(targetJsDirectory, targetFileName);
        logger.debug("target file = " + destFile);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        boolean isLastFileAJson = false;
        for (File srcFile : files) {
            logger.debug("including file = " + srcFile);
            if ((isJson(srcFile) || isYaml(srcFile)) && isLastFileAJson) {
                IOUtils.write(",", out);
            }
            String data = readFile(srcFile);
            IOUtils.write("\n\n/** BEGIN FILE " + srcFile.getName() + " **/\n\n", out);
            IOUtils.write(data, out);
            IOUtils.write("\n\n/** END FILE " + srcFile.getName() + " **/\n\n", out);
            isLastFileAJson = (isJson(srcFile) || isYaml(srcFile));
        }
        out.close();
        byte[] jsData = out.toByteArray();
        if (compressJs) {
            logger.debug("compressing with closure-compiler");
            Compiler compiler = new Compiler();
            CompilerOptions options = new CompilerOptions();
            SourceFile inputFile = SourceFile.fromInputStream(targetFileName, new ByteArrayInputStream(jsData));
            compiler.compile(SourceFile.fromCode("external.js", ""), inputFile, options);
            jsData = compiler.toSource().getBytes();
        }
        FileUtils.writeByteArrayToFile(destFile, jsData);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy