org.jsweet.plugin.builder.JSweetBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.jsweet.plugin.builder.JSweetBuilder.java

Source

/*
 * Copyright 2015 CINCHEO SAS <renaud.pawlak@cincheo.fr>
 *
 * 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.jsweet.plugin.builder;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ui.PreferenceConstants;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
import org.jsweet.JSweetConfig;
import org.jsweet.plugin.Log;
import org.jsweet.plugin.preferences.Preferences;
import org.jsweet.transpiler.JSweetProblem;
import org.jsweet.transpiler.JSweetTranspiler;
import org.jsweet.transpiler.ModuleKind;
import org.jsweet.transpiler.Severity;
import org.jsweet.transpiler.SourceFile;
import org.jsweet.transpiler.SourcePosition;
import org.jsweet.transpiler.TranspilationHandler;
import org.jsweet.transpiler.candies.CandiesProcessor;
import org.jsweet.transpiler.util.Util;

public class JSweetBuilder extends IncrementalProjectBuilder {

    public static final String ID = "org.jsweet.plugin.jsweetBuilder";
    public static final String JSWEET_PROBLEM_MARKER_TYPE = "org.jsweet.plugin.jsweetProblem";

    static class BuildingContext {
        public final String profile;
        public final IProject project;
        // watch mode does not work (yet?) under Windows, so we do not use it
        public boolean USE_WATCH_MODE = false;
        public final Map<File, SourceFile> sourceFiles = new HashMap<>();
        public JSweetTranspiler transpiler;

        public BuildingContext(IProject project, String profile) {
            this.project = project;
            this.profile = profile;
        }
    }

    private static boolean hasFile(File folder) {
        if (folder.isDirectory()) {
            File[] files = folder.listFiles();
            if (files != null) {
                for (File file : folder.listFiles()) {
                    if (file.isFile()) {
                        return true;
                    } else {
                        return hasFile(file);
                    }
                }
            }
        }
        return false;
    }

    private static void cleanFiles(BuildingContext context) throws CoreException {
        try {
            context.project.deleteMarkers(JSWEET_PROBLEM_MARKER_TYPE, true, IResource.DEPTH_INFINITE);
            File tsOutDir = new File(context.project.getLocation().toFile(),
                    Preferences.getTsOutputFolder(context.project, context.profile));
            LinkedList<File> files = new LinkedList<>();
            if (tsOutDir.exists()) {
                Util.addFiles(".ts", tsOutDir, files);
                for (File f : files) {
                    FileUtils.deleteQuietly(f);
                }
                if (!hasFile(tsOutDir)) {
                    FileUtils.deleteQuietly(tsOutDir);
                }
            }
            files.clear();
            File jsOutDir = new File(context.project.getLocation().toFile(),
                    Preferences.getJsOutputFolder(context.project, context.profile));
            if (jsOutDir.exists()) {
                Util.addFiles(".js", jsOutDir, files);
                Util.addFiles(".js.map", jsOutDir, files);
                for (File f : files) {
                    FileUtils.deleteQuietly(f);
                }
                if (!hasFile(jsOutDir)) {
                    FileUtils.deleteQuietly(jsOutDir);
                }
            }
            context.project.refreshLocal(IResource.DEPTH_INFINITE, null);
        } catch (NoClassDefFoundError e) {
            e.printStackTrace();
        }
    }

    private static void autoFillClassPath(IProject project) throws CoreException {
        if (project.isNatureEnabled("org.eclipse.jdt.core.javanature")) {
            IJavaProject javaProject = JavaCore.create(project);
            IClasspathEntry[] cp = javaProject.getRawClasspath();
            File processed = project.getLocation().append(JSweetTranspiler.TMP_WORKING_DIR_NAME + File.separator
                    + CandiesProcessor.CANDIES_PROCESSED_DIR_NAME).toFile();
            IClasspathEntry e = javaProject.decodeClasspathEntry(
                    "<classpathentry kind=\"lib\" path=\"" + JSweetTranspiler.TMP_WORKING_DIR_NAME + File.separator
                            + CandiesProcessor.CANDIES_PROCESSED_DIR_NAME + "\" sourcepath=\""
                            + JSweetTranspiler.TMP_WORKING_DIR_NAME + File.separator
                            + CandiesProcessor.CANDIES_SOURCES_DIR_NAME + "\" />");
            if (project.isNatureEnabled(JSweetNature.ID)) {
                if (!processed.exists()) {
                    processed.mkdirs();
                    project.refreshLocal(IResource.DEPTH_INFINITE, null);
                }
                if (!ArrayUtils.contains(cp, e)) {
                    Log.info("adding " + e + " to build path");
                    cp = ArrayUtils.add(cp, 0, e);
                    javaProject.setRawClasspath(cp, true, null);
                }
            } else {
                if (ArrayUtils.contains(cp, e)) {
                    Log.info("removing " + e + " from build path");
                    cp = ArrayUtils.remove(cp, ArrayUtils.indexOf(cp, e));
                    javaProject.setRawClasspath(cp, true, null);
                }
            }
        }
    }

    public static void clean(IProject project, IProgressMonitor monitor) throws CoreException {
        // adds processed class directory to the build path to ensure that
        // mixins are available
        File tmp = project.getLocation().append(JSweetTranspiler.TMP_WORKING_DIR_NAME).toFile();
        FileUtils.deleteQuietly(tmp);
        autoFillClassPath(project);
        // delete markers set and files created
        for (String profile : Preferences.parseProfiles(project)) {
            cleanFiles(new BuildingContext(project, profile));
        }
    }

    /**
     * Forces a full clean/rebuild of all the workspace projects that have the
     * JSweet nature.
     */
    public static void rebuildWorkspace() {
        IWorkspace workspace = ResourcesPlugin.getWorkspace();
        rebuildProjects(Arrays.asList(workspace.getRoot().getProjects()));
    }

    /**
     * Forces a full clean of all the workspace projects that have the JSweet
     * nature.
     */
    public static void cleanWorkspace() {
        IWorkspace workspace = ResourcesPlugin.getWorkspace();
        cleanProjects(Arrays.asList(workspace.getRoot().getProjects()));
    }

    /**
     * Forces a full clean rebuild of the given JSweet project.
     */
    public static void rebuildProject(IProject project) {
        rebuildProjects(Arrays.asList(project));
    }

    /**
     * Forces a clean of the given JSweet project.
     */
    public static void cleanProject(IProject project) {
        rebuildProjects(Arrays.asList(project));
    }

    private static void rebuildProjects(final List<IProject> projects) {
        String name = "rebuild";// Resources.BUNDLE.getString("preferences.compiler.rebuild.job.name");
        Job job = new Job(name) {
            @Override
            protected IStatus run(IProgressMonitor monitor) {
                try {
                    for (IProject project : projects) {
                        if (project.isOpen() && project.hasNature(JSweetNature.ID)) {
                            project.build(IncrementalProjectBuilder.CLEAN_BUILD, JSweetBuilder.ID, null, monitor);
                            project.build(IncrementalProjectBuilder.FULL_BUILD, JSweetBuilder.ID, null, monitor);
                        }
                    }
                    return Status.OK_STATUS;
                } catch (CoreException e) {
                    return e.getStatus();
                }
            }
        };
        job.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
        job.schedule();
    }

    private static void cleanProjects(final List<IProject> projects) {
        String name = "clean";// Resources.BUNDLE.getString("preferences.compiler.rebuild.job.name");
        Job job = new Job(name) {
            @Override
            protected IStatus run(IProgressMonitor monitor) {
                try {
                    for (IProject project : projects) {
                        if (project.isOpen() && project.hasNature(JSweetNature.ID)) {
                            project.build(IncrementalProjectBuilder.CLEAN_BUILD, JSweetBuilder.ID, null, monitor);
                        }
                    }
                    return Status.OK_STATUS;
                } catch (CoreException e) {
                    return e.getStatus();
                }
            }
        };
        job.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
        job.schedule();
    }

    class IncrementalGrabJavaFileVisitor implements IResourceDeltaVisitor {
        private IJavaProject project;
        private BuildingContext context;
        public List<File> javaFiles = new ArrayList<File>();
        public List<IFile> javaResourceFiles = new ArrayList<IFile>();

        public IncrementalGrabJavaFileVisitor(IJavaProject project, BuildingContext context) {
            this.project = project;
            this.context = context;
        }

        private void grabJavaFileHierarchy(IResource resource) throws JavaModelException, CoreException {
            IFile resourceFile = (IFile) resource;
            File file = new File(resource.getProject().getLocation().toFile(),
                    resourceFile.getProjectRelativePath().toFile().toString());
            if (!javaFiles.contains(file)) {
                javaFiles.add(file);
                javaResourceFiles.add(resourceFile);
                IPackageFragment packge = project.findPackageFragment(resource.getParent().getFullPath());
                if (packge != null && packge.getCompilationUnits() != null) {
                    for (ICompilationUnit cu : packge.getCompilationUnits()) {
                        if (cu.getResource().equals(resource)) {
                            for (IType t1 : cu.getAllTypes()) {
                                for (IType t2 : t1.newTypeHierarchy(project, null).getAllTypes()) {
                                    IResource r = t2.getResource();
                                    if (r instanceof IFile && resource.getName().endsWith(".java")) {
                                        resourceFile = (IFile) r;
                                        file = new File(r.getProject().getLocation().toFile(),
                                                resourceFile.getProjectRelativePath().toFile().toString());
                                        if (!javaFiles.contains(file)) {
                                            javaFiles.add(file);
                                            javaResourceFiles.add(resourceFile);
                                        }
                                    }
                                }

                            }
                        }
                    }
                }
            }
        }

        public boolean visit(IResourceDelta delta) throws CoreException {
            IResource resource = delta.getResource();
            if (resource instanceof IFile && resource.getName().endsWith(".java")) {
                switch (delta.getKind()) {
                case IResourceDelta.ADDED:
                    if (context.USE_WATCH_MODE && context.transpiler != null) {
                        context.transpiler.resetTscWatchMode();
                    }
                    grabJavaFileHierarchy(resource);
                    break;
                case IResourceDelta.REMOVED:
                    deleteMarkers((IFile) resource);
                    SourceFile sf;
                    if (context.USE_WATCH_MODE && context.transpiler != null) {
                        File file = new File(resource.getProject().getLocation().toFile(),
                                ((IFile) resource).getProjectRelativePath().toFile().toString());
                        sf = context.transpiler.getWatchedFile(file);
                        context.transpiler.resetTscWatchMode();
                    } else {
                        File file = new File(resource.getProject().getLocation().toFile(),
                                ((IFile) resource).getProjectRelativePath().toFile().toString());
                        sf = context.sourceFiles.get(file);
                        context.sourceFiles.remove(file);
                    }
                    if (sf != null) {
                        File tsFile = sf.getTsFile();
                        File jsFile = sf.getJsFile();
                        File jsMapFile = sf.getJsFile();
                        FileUtils.deleteQuietly(tsFile);
                        FileUtils.deleteQuietly(jsFile);
                        FileUtils.deleteQuietly(jsMapFile);
                    }
                    break;
                case IResourceDelta.CHANGED:
                    grabJavaFileHierarchy(resource);
                    break;
                }
            }
            // return true to continue visiting children.
            return true;
        }
    }

    private static boolean isIncluded(BuildingContext context, IPath path) {
        if (!StringUtils.isBlank(Preferences.getSourceIncludeFilter(context.project, context.profile))) {
            if (!path.toString().matches(Preferences.getSourceIncludeFilter(context.project, context.profile))) {
                Log.info("excluded by included filer: " + path);
                return false;
            }
        }
        if (!StringUtils.isBlank(Preferences.getSourceExcludeFilter(context.project, context.profile))) {
            if (path.toString().matches(Preferences.getSourceExcludeFilter(context.project, context.profile))) {
                Log.info("excluded by excluded filer: " + path);
                return false;
            }
        }
        Log.info("include: " + path);
        return true;
    }

    class GrabJavaFilesVisitor implements IResourceVisitor {
        private BuildingContext context;
        public List<File> javaFiles = new ArrayList<File>();
        public List<IPath> sourceDirs;

        public GrabJavaFilesVisitor(BuildingContext context, List<IPath> sourceDirs) {
            this.context = context;
            this.sourceDirs = sourceDirs;
        }

        public boolean visit(IResource resource) {
            if (resource instanceof IFile && resource.getName().endsWith(".java")) {
                IFile file = (IFile) resource;
                if (file.getProjectRelativePath().segment(0).equals(JSweetTranspiler.TMP_WORKING_DIR_NAME)) {
                    return true;
                }
                if (!sourceDirs.isEmpty()) {
                    for (IPath sourcePath : sourceDirs) {
                        if (sourcePath.isPrefixOf(file.getFullPath())) {
                            IPath relativePath = file.getFullPath().makeRelativeTo(sourcePath);
                            if (isIncluded(context, relativePath)) {
                                javaFiles.add(new File(resource.getProject().getLocation().toFile(),
                                        file.getProjectRelativePath().toFile().toString()));
                            }
                            return true;
                        }
                    }
                } else {
                    if (isIncluded(context, file.getProjectRelativePath())) {
                        javaFiles.add(new File(resource.getProject().getLocation().toFile(),
                                file.getProjectRelativePath().toFile().toString()));
                    }
                }
            }
            // return true to continue visiting children.
            return true;
        }
    }

    class JSweetTranspilationHandler implements TranspilationHandler {

        BuildingContext context;

        public JSweetTranspilationHandler(BuildingContext context) {
            this.context = context;
        }

        @Override
        public void report(JSweetProblem problem, SourcePosition sourcePosition, String message) {
            if (problem == JSweetProblem.INTERNAL_JAVA_ERROR) {
                // ignore Java errors because they will be reported by Eclipse
                return;
            }
            String base = context.project.getLocation().toFile().getAbsolutePath();
            if (sourcePosition == null || sourcePosition.getFile() == null) {
                addMarker(context.project, message, -1, -1, -1,
                        problem.getSeverity() == Severity.ERROR ? IMarker.SEVERITY_ERROR
                                : IMarker.SEVERITY_WARNING);
            } else {
                IFile f = null;
                try {
                    f = (IFile) context.project
                            .findMember(sourcePosition.getFile().getAbsolutePath().substring(base.length() + 1));
                } catch (Exception e) {
                    // swallow
                }
                if (f == null) {
                    try {
                        f = (IFile) context.project.findMember(sourcePosition.getFile().getPath());
                    } catch (Exception e) {
                        // swallow
                    }
                }
                if (f == null) {
                    addMarker(context.project, message, -1, -1, -1,
                            problem.getSeverity() == Severity.ERROR ? IMarker.SEVERITY_ERROR
                                    : IMarker.SEVERITY_WARNING);
                } else {
                    addMarker(f, message, sourcePosition.getStartLine(),
                            sourcePosition.getStartPosition().getPosition(),
                            sourcePosition.getEndPosition().getPosition(),
                            problem.getSeverity() == Severity.ERROR ? IMarker.SEVERITY_ERROR
                                    : IMarker.SEVERITY_WARNING);
                }
            }
        }

        @Override
        public void onCompleted(JSweetTranspiler transpiler, boolean fullPass, SourceFile[] files) {
            try {
                if (fullPass) {
                    Log.info("refreshing worspace (full)");
                    context.project.refreshLocal(IResource.DEPTH_INFINITE, null);
                } else {
                    // TODO: refresh only the resources that have changed (using
                    // the files argument)
                    Log.info("refreshing output directories (incremental)");
                    final IResource output = context.project
                            .findMember(Preferences.getTsOutputFolder(context.project, context.profile));
                    final IResource jsOutput = context.project
                            .findMember(Preferences.getJsOutputFolder(context.project, context.profile));
                    if (output != null || jsOutput != null) {
                        new Thread() {
                            public void run() {
                                try {
                                    if (output != null) {
                                        output.refreshLocal(IResource.DEPTH_INFINITE, null);
                                    }
                                    if (jsOutput != null && !jsOutput.equals(output)) {
                                        jsOutput.refreshLocal(IResource.DEPTH_INFINITE, null);
                                    }
                                } catch (CoreException e) {
                                    Log.error("error while refreshing", e);
                                }
                            }
                        }.start();
                    }
                }

            } catch (Exception e) {
                Log.error(e);
            }
        }

    }

    private void addMarker(IResource resource, String message, int lineNumber, int charStart, int charEnd,
            int severity) {
        try {
            IMarker marker = resource.createMarker(JSWEET_PROBLEM_MARKER_TYPE);
            marker.setAttribute(IMarker.MESSAGE, message);
            marker.setAttribute(IMarker.SEVERITY, severity);
            if (lineNumber >= 0) {
                marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
            }
            if (charStart >= 0) {
                marker.setAttribute(IMarker.CHAR_START, charStart);
            }
            if (charEnd >= 0) {
                marker.setAttribute(IMarker.CHAR_END, charEnd);
            }
        } catch (CoreException e) {
            Log.error(e);
        }
    }

    protected IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException {
        // Only full builds are supported for now... incremental builds should
        // be supported later if possible

        // addResourceChangeListener();
        // if (!USE_WATCH_MODE || kind == FULL_BUILD) {
        // fullBuild(monitor);
        // } else {
        // IResourceDelta delta = getDelta(getProject());
        // if (delta == null) {
        // fullBuild(monitor);
        // } else {
        // incrementalBuild(delta, monitor);
        // }
        // }
        for (String profile : Preferences.parseProfiles(getProject())) {
            fullBuild(new BuildingContext(getProject(), profile), monitor);
        }
        forceStaticImports();
        return null;
    }

    private String[] defaultFavorites = { JSweetConfig.LANG_PACKAGE + "." + JSweetConfig.GLOBALS_CLASS_NAME + ".*",
            JSweetConfig.UTIL_CLASSNAME + ".*",
            JSweetConfig.DOM_PACKAGE + "." + JSweetConfig.GLOBALS_CLASS_NAME + ".*",
            JSweetConfig.LIBS_PACKAGE + ".jquery." + JSweetConfig.GLOBALS_CLASS_NAME + ".*",
            JSweetConfig.LIBS_PACKAGE + ".underscore." + JSweetConfig.GLOBALS_CLASS_NAME + ".*" };

    private void forceStaticImports() {
        try {
            IPreferenceStore s = new ScopedPreferenceStore(InstanceScope.INSTANCE, "org.eclipse.jdt.ui");
            String favorites = s.getString(PreferenceConstants.CODEASSIST_FAVORITE_STATIC_MEMBERS);
            for (String f : defaultFavorites) {
                if (!favorites.contains(f)) {
                    if (!favorites.isEmpty()) {
                        favorites += ";";
                    }
                    favorites += f;
                }
            }
            Log.info("forcing favorite static members: " + favorites);
            s.setValue(PreferenceConstants.CODEASSIST_FAVORITE_STATIC_MEMBERS, favorites);
        } catch (Exception e) {
            Log.error(e);
        }
    }

    @Override
    protected void clean(IProgressMonitor monitor) throws CoreException {
        clean(getProject(), monitor);
    }

    private void deleteMarkers(IFile... files) {
        try {
            for (IFile file : files) {
                file.deleteMarkers(JSWEET_PROBLEM_MARKER_TYPE, false, IResource.DEPTH_ZERO);
            }
        } catch (CoreException ce) {
            Log.error(ce);
        }
    }

    private void transpileFiles(BuildingContext context, File... files) {
        try {
            if (context.transpiler == null || files == null || files.length == 0) {
                return;
            }
            Log.info("compiling " + Arrays.asList(files));
            SourceFile[] sfs = SourceFile.toSourceFiles(files);
            for (SourceFile sf : sfs) {
                context.sourceFiles.put(sf.getJavaFile(), sf);
            }
            context.transpiler.transpile(new JSweetTranspilationHandler(context), sfs);
        } catch (Throwable t) {
            Log.error("cannot compile", t);
        }
    }

    private void fullBuild(BuildingContext context, final IProgressMonitor monitor) throws CoreException {
        Log.info("JSweet: full build...");
        context.project.deleteMarkers(JSWEET_PROBLEM_MARKER_TYPE, true, IResource.DEPTH_INFINITE);
        List<IPath> sourceDirs = new ArrayList<>();
        if (!StringUtils.isEmpty(Preferences.getSourceFolders(context.project, context.profile))) {
            String[] names = Preferences.getSourceFolders(context.project, context.profile).split("[,;]");
            try {
                for (String name : names) {
                    sourceDirs.add(context.project.getFolder(name).getFullPath());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        String jdkHome = null;
        boolean lookupSourceFolder = sourceDirs.isEmpty();
        if (context.project.isNatureEnabled("org.eclipse.jdt.core.javanature")) {
            IJavaProject javaProject = JavaCore.create(context.project);
            IClasspathEntry[] classPathEntries = javaProject.getResolvedClasspath(true);
            for (IClasspathEntry e : classPathEntries) {
                if (lookupSourceFolder && e.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
                    sourceDirs.add(e.getPath());
                } else if (e.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
                    if (e.getPath().toString().endsWith("/lib/rt.jar")) {
                        jdkHome = e.getPath().removeLastSegments(2).toString();
                    }
                }
            }
        }
        Log.info("source dirs: " + sourceDirs);
        GrabJavaFilesVisitor v = new GrabJavaFilesVisitor(context, sourceDirs);

        context.project.accept(v);
        context.sourceFiles.clear();
        Log.info("init classpath, jdkHome: " + jdkHome);
        JSweetConfig.initClassPath(jdkHome);
        createJSweetTranspiler(context);
        transpileFiles(context, v.javaFiles.toArray(new File[0]));
    }

    private class CheckIfRemovedInDelta implements IResourceDeltaVisitor {
        public boolean result = false;

        @Override
        public boolean visit(IResourceDelta delta) throws CoreException {
            if (delta.getKind() == IResourceDelta.REMOVED) {
                result = true;
            }
            return true;
        }
    }

    protected void incrementalBuild(BuildingContext context, IResourceDelta delta, IProgressMonitor monitor)
            throws CoreException {
        if (context.project.isNatureEnabled("org.eclipse.jdt.core.javanature")) {
            Log.info("JSweet: incremental build...");
            CheckIfRemovedInDelta removed = new CheckIfRemovedInDelta();
            delta.accept(removed);
            if (removed.result) {
                // we should delete only the removed file
                cleanFiles(context);
                fullBuild(context, monitor);
            } else {
                IJavaProject javaProject = JavaCore.create(context.project);
                IncrementalGrabJavaFileVisitor v = new IncrementalGrabJavaFileVisitor(javaProject, context);
                delta.accept(v);
                deleteMarkers(v.javaResourceFiles.toArray(new IFile[0]));
                context.project.deleteMarkers(JSWEET_PROBLEM_MARKER_TYPE, true, IResource.DEPTH_ZERO);
                if (context.transpiler == null) {
                    createJSweetTranspiler(context);
                }
                transpileFiles(context, v.javaFiles.toArray(new File[0]));
            }
        } else {
            // no support for incremental build
            fullBuild(context, monitor);
        }

    }

    private void createJSweetTranspiler(BuildingContext context) throws CoreException {
        if (context.USE_WATCH_MODE && context.transpiler != null) {
            Log.info("stopping tsc watch mode");
            context.transpiler.setTscWatchMode(false);
            Log.info("tsc watch mode stopped");
        }
        StringBuilder classPath = new StringBuilder();
        if (context.project.isNatureEnabled("org.eclipse.jdt.core.javanature")) {
            IJavaProject javaProject = JavaCore.create(context.project);
            IClasspathEntry[] classPathEntries = javaProject.getResolvedClasspath(true);
            for (IClasspathEntry e : classPathEntries) {
                classPath.append(resolve(context.project, e.getPath()).toString());
                classPath.append(File.pathSeparator);
            }
        }
        Log.info("compiling with classpath: " + classPath.toString());
        File jsOutputFolder = new File(context.project.getLocation().toFile(),
                Preferences.getJsOutputFolder(context.project, context.profile));
        try {
            context.transpiler = new JSweetTranspiler(
                    new File(context.project.getLocation().toFile(), JSweetTranspiler.TMP_WORKING_DIR_NAME),
                    new File(context.project.getLocation().toFile(),
                            Preferences.getTsOutputFolder(context.project, context.profile)),
                    jsOutputFolder,
                    new File(context.project.getLocation().toFile(),
                            Preferences.getCandyJsOutputFolder(context.project, context.profile)),
                    classPath.toString());
            context.transpiler
                    .setPreserveSourceLineNumbers(Preferences.isJavaDebugMode(context.project, context.profile));
            String moduleString = Preferences.getModuleKind(context.project, context.profile);
            context.transpiler.setModuleKind(
                    StringUtils.isBlank(moduleString) ? ModuleKind.none : ModuleKind.valueOf(moduleString));
            String bundleDirectory = Preferences.getBundlesDirectory(context.project, context.profile);
            if (!StringUtils.isBlank(bundleDirectory)) {
                File f = new File(bundleDirectory);
                if (!f.isAbsolute()) {
                    f = new File(context.project.getLocation().toFile(), bundleDirectory);
                }
                context.transpiler.setBundlesDirectory(f);
            }
            context.transpiler.setBundle(Preferences.getBundle(context.project, context.profile));
            context.transpiler
                    .setGenerateDeclarations(Preferences.getDeclaration(context.project, context.profile));
            String declarationDirectory = Preferences.getDeclarationDirectory(context.project, context.profile);
            if (!StringUtils.isBlank(declarationDirectory)) {
                File f = new File(declarationDirectory);
                if (!f.isAbsolute()) {
                    f = new File(context.project.getLocation().toFile(), declarationDirectory);
                }
                context.transpiler.setDeclarationsOutputDir(f);
            }

            // transpiler.setTsDefDirs(new
            // File(context.project.getLocation().toFile(),
            // Preferences
            // .getTsOutputFolder(context.project)));
            if (context.USE_WATCH_MODE) {
                context.transpiler.setTscWatchMode(true);
            }
        } catch (NoClassDefFoundError error) {
            new JSweetTranspilationHandler(context).report(JSweetProblem.JAVA_COMPILER_NOT_FOUND, null,
                    JSweetProblem.JAVA_COMPILER_NOT_FOUND.getMessage());
        }
    }

    private static File resolve(IProject project, IPath path) {
        String string = path.toString();
        if (path.isAbsolute()) {
            File f = new File(string);
            if (f.exists()) {
                return f;
            } else {
                return new File(project.getWorkspace().getRoot().getLocation().toFile(), string);
            }
        } else {
            return new File(project.getLocation().toFile(), string);
        }
    }

}