com.htmlhifive.tools.jslint.parse.JsParser.java Source code

Java tutorial

Introduction

Here is the source code for com.htmlhifive.tools.jslint.parse.JsParser.java

Source

/*
 * Copyright (C) 2012 NS Solutions Corporation
 *
 * 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 com.htmlhifive.tools.jslint.parse;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.script.ScriptException;

import org.apache.commons.lang.StringUtils;
import org.eclipse.core.resources.IContainer;
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.IResourceVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;

import com.htmlhifive.tools.jslint.JSLintPlugin;
import com.htmlhifive.tools.jslint.JSLintPluginConstant;
import com.htmlhifive.tools.jslint.configure.ConfigBean;
import com.htmlhifive.tools.jslint.configure.FilterBean;
import com.htmlhifive.tools.jslint.configure.FilterBean.FilterLevel;
import com.htmlhifive.tools.jslint.configure.JSLintConfigManager;
import com.htmlhifive.tools.jslint.engine.JSChecker;
import com.htmlhifive.tools.jslint.engine.JSCheckerErrorBean;
import com.htmlhifive.tools.jslint.engine.JSCheckerFactory;
import com.htmlhifive.tools.jslint.engine.JSCheckerResult;
import com.htmlhifive.tools.jslint.engine.option.CheckOption;
import com.htmlhifive.tools.jslint.engine.option.CheckOptionFileWrapper;
import com.htmlhifive.tools.jslint.engine.option.CheckOptionFileWrapperFactory;
import com.htmlhifive.tools.jslint.engine.option.Engine;
import com.htmlhifive.tools.jslint.engine.option.JSHintDefaultOptions;
import com.htmlhifive.tools.jslint.logger.JSLintPluginLogger;
import com.htmlhifive.tools.jslint.logger.JSLintPluginLoggerFactory;
import com.htmlhifive.tools.jslint.messages.Messages;
import com.htmlhifive.tools.jslint.util.ConfigBeanUtil;
import com.htmlhifive.tools.jslint.util.PluginResourceUtils;

/**
 * JSlint??????.
 * 
 * @author NS Solutions Corporation
 * 
 */
public class JsParser implements Parser {

    /**
     * .
     */
    private static JSLintPluginLogger logger = JSLintPluginLoggerFactory.getLogger(JsParser.class);

    /**
     * js???.
     */
    private static final int TASK_PARSE_JS = 1000;

    /**
     * ???.
     */
    private static final int TASK_MARK_VIEW = 600;

    /**
     * JS???.
     */
    private static final int TASK_SERCH_JS = 50;

    /**
     * JSLint.js????.
     */
    private static final int TASK_LOAD_JSLINT = 50;

    /**
     * ???.
     */
    private static final int TASK_ALL = TASK_PARSE_JS + TASK_MARK_VIEW + TASK_SERCH_JS + TASK_LOAD_JSLINT;

    /**
     * ?.
     */
    private IProgressMonitor monitor = null;

    /**
     * ??(???).
     */
    private IResource resource;

    /**
     * ???.
     */
    private ConfigBean bean;

    /**
     * ???.
     */
    private int maxerr = 50;

    /**
     * .
     * 
     * @param resource ??.
     * @param monitor
     */
    public JsParser(IResource resource) {

        this.resource = resource;
        IProject project = resource.getProject();
        ConfigBean configBean = JSLintConfigManager.getConfigBean(project);

        if (configBean.isUseOtherProject()) {
            bean = JSLintConfigManager.getConfigBean(
                    (IProject) PluginResourceUtils.pathToContainer(configBean.getOtherProjectPath()));
            bean.setExternalLibPathList(configBean.getExternalLibPathList());
            bean.setInternalLibPathList(configBean.getInternalLibPathList());
        } else {
            bean = configBean;
        }
        logger.debug("use project path : " + bean.getOtherProjectPath());
    }

    @Override
    public synchronized JsParseResult parse(IProgressMonitor monitor) throws CoreException, InterruptedException {

        try {
            ParserManager.replaceCurrentParser(this);
            this.monitor = monitor;
            // ?
            String[] errorMessages = ConfigBeanUtil.checkProperty(bean);
            if (errorMessages.length > 0) {
                throwCoreException(IStatus.WARNING, errorMessages);
            }
            checkCancel();
            monitor.beginTask(Messages.T0000.getText(), TASK_ALL);
            monitor.subTask(Messages.T0001.getText());

            monitor.worked(TASK_SERCH_JS);
            monitor.subTask(Messages.T0002.getText());
            logger.debug("prop file is " + bean.getOptionFilePath());
            checkCancel();
            // ??,?.
            checkCancel();
            IFile jslintFile = (IFile) ResourcesPlugin.getWorkspace().getRoot().findMember(bean.getJsLintPath());
            long parseStart = System.currentTimeMillis();

            // ??.
            checkCancel();
            Engine engine = getEngine(jslintFile);

            // ??
            CheckOptionFileWrapper option = null;
            CheckOption[] newOptions = null;
            if (StringUtils.isNotEmpty(bean.getOptionFilePath())) {
                IFile propFile = (IFile) ResourcesPlugin.getWorkspace().getRoot()
                        .findMember(bean.getOptionFilePath());
                option = CheckOptionFileWrapperFactory.createCheckOptionFileWrapper(propFile);
                if (option.getOptions(engine).length != 0) {
                    // ?.
                    String maxerrStr = option.getOption("maxerr", engine.getKey()).getValue();
                    if (maxerrStr != null) {
                        maxerr = Integer.parseInt(maxerrStr);
                    }
                    CheckOption[] options = option.getEnableOptions(engine);
                    newOptions = handleMaxerr(options);
                }

            }

            logger.debug("jslint file is " + bean.getJsLintPath());
            checkCancel();

            JSChecker jsLint = JSCheckerFactory.createJSChecker(jslintFile, newOptions);
            logger.debug("create checker time" + String.valueOf(System.currentTimeMillis() - parseStart));
            monitor.worked(TASK_LOAD_JSLINT);
            monitor.setTaskName(Messages.T0003.getText());
            long getLibStart = System.currentTimeMillis();
            // ??.
            JsFileInfo libStr = getLibrary();
            logger.debug("get lib time " + String.valueOf(System.currentTimeMillis() - getLibStart));
            checkCancel();

            // ??.
            IFile[] jsFiles = getJsFile();
            beforeCheck();
            // ??.
            List<JsMarkingSupport> markList = new ArrayList<JsMarkingSupport>();
            for (IFile iFile : jsFiles) {
                checkCancel();
                monitor.subTask(Messages.T0006.format(iFile.getName()));
                logger.debug("targetFile : " + iFile.getName());
                JsFileInfo target = null;
                JsFileInfo fileInfo = new JsFileInfo(iFile);
                JSCheckerResult result = null;
                if (libStr != null) {
                    target = libStr.clone();
                    target.append(fileInfo);
                } else {
                    target = fileInfo.clone();
                }
                beforeCheckAtFile(iFile);
                checkCancel();
                long parseAtFileStart = System.currentTimeMillis();
                result = jsLint.lint(target.getSourceStr());
                logger.debug("parse at file time" + String.valueOf(System.currentTimeMillis() - parseAtFileStart));
                addMakingList(markList, iFile, result.getErrors(), libStr != null ? libStr.getLineCount() : 0);
                // ?????
                monitor.worked(TASK_PARSE_JS / jsFiles.length);
            }
            monitor.setTaskName(Messages.T0007.getText());
            mark(markList);
            logger.debug("parse time : " + String.valueOf(System.currentTimeMillis() - parseStart));
            monitor.subTask(Messages.T0004.getText());
            monitor.done();
            ParserManager.clearCurrentParser();

            JsParseResult jsParseResult = new JsParseResult();
            jsParseResult.setErrorCount(markList.size());
            return jsParseResult;
        } catch (IOException e) {
            logger.put(Messages.EM0100, e);
            throw new CoreException(new Status(IStatus.ERROR, JSLintPlugin.PLUGIN_ID, null, e));
        } catch (ScriptException e) {
            throw new CoreException(new Status(IStatus.WARNING, JSLintPlugin.PLUGIN_ID, null, e));
        }
    }

    /**
     * ????????.
     * 
     * @throws InterruptedException .
     */
    private void checkCancel() throws InterruptedException {

        if (monitor.isCanceled()) {
            ParserManager.clearCurrentParser();
            throw new InterruptedException();
        }

    }

    /**
     * ?options?maxerr??.<br>
     * ??????JSLint????????,<br>
     * ??????????????maxerr??????
     * 
     * @param options .
     * @return ??.
     */
    private CheckOption[] handleMaxerr(CheckOption[] options) {

        List<CheckOption> newOptionList = new ArrayList<CheckOption>();
        boolean containMaxerr = false;
        for (CheckOption checkOption : options) {
            logger.debug("option : " + checkOption.toString());

            if ("maxerr".equals(checkOption.getKey())) {
                checkOption.setValue(String.valueOf(Integer.MAX_VALUE));
                containMaxerr = true;
            }
            newOptionList.add(checkOption);
        }
        if (containMaxerr) {
            return (CheckOption[]) newOptionList.toArray(new CheckOption[newOptionList.size()]);
        }
        // ??????maxerr??.
        CheckOption maxerrOption = JSHintDefaultOptions.MAXERR.convertToOption();
        newOptionList.add(maxerrOption);
        return (CheckOption[]) newOptionList.toArray(new CheckOption[newOptionList.size()]);
    }

    /**
     * ?Engine??.
     * 
     * @param jslintFile .
     * @return Engine.
     */
    private Engine getEngine(IFile jslintFile) {

        if (JSLintPluginConstant.JS_LINT_NAME.equals(jslintFile.getName())) {
            return Engine.JSLINT;
        } else {
            return Engine.JSHINT;
        }
    }

    /**
     * parse?????.
     * 
     * @throws CoreException ?.
     */
    void beforeCheck() throws CoreException {

    }

    /**
     * ?????.
     * 
     * @param file ?.
     * @throws CoreException ?.
     */
    void beforeCheckAtFile(IFile file) throws CoreException {

        file.deleteMarkers(JSLintPluginConstant.JS_TYPE_MARKER, true, IResource.DEPTH_INFINITE);
    }

    /**
     * ???.
     * 
     * @return .
     * @throws CoreException ?.
     */
    protected JsFileInfo getLibrary() throws CoreException {

        return null;
    }

    /**
     * ?Js??.
     * 
     * @param jsFileList
     * @return ?Js
     * @throws CoreException ?.
     */
    protected IFile[] getJsFile() throws CoreException {

        final List<IFile> jsFileList = new ArrayList<IFile>();
        if (resource instanceof IContainer) {
            IContainer container = (IContainer) resource;
            // ?js?.
            container.accept(new IResourceVisitor() {
                @Override
                public boolean visit(IResource resource) throws CoreException {

                    if (JSLintPluginConstant.EXTENTION_JS.equals(resource.getFileExtension())) {
                        jsFileList.add((IFile) resource);
                    }
                    return true;
                }
            });
        } else if (JSLintPluginConstant.EXTENTION_JS.equals(resource.getFileExtension())) {
            jsFileList.add((IFile) resource);
        } else {
            // ???????
            throw new AssertionError();
        }
        return (IFile[]) jsFileList.toArray(new IFile[jsFileList.size()]);
    }

    /**
     * CoreExceptin?.
     * 
     * @param severity .
     * @param messages .
     * @throws CoreException CoreException
     */
    private void throwCoreException(int severity, String... messages) throws CoreException {

        MultiStatus multiStatus = new MultiStatus(JSLintPlugin.PLUGIN_ID, IStatus.OK, Messages.EM0001.getText(),
                null);
        for (String string : messages) {
            IStatus iStatus = new Status(severity, JSLintPlugin.PLUGIN_ID, string, null);
            multiStatus.add(iStatus);
        }
        throw new CoreException(multiStatus);

    }

    /**
     * ???.
     * 
     * @param list .
     * @param iFile ?js.
     * @param errors .
     * @param startPosition ?.
     * @throws CoreException .
     */
    private void addMakingList(List<JsMarkingSupport> list, IFile iFile, JSCheckerErrorBean[] errors,
            int startPosition) throws CoreException {
        int i = 0;
        for (JSCheckerErrorBean jsLintError : errors) {

            if (jsLintError.getLine() > startPosition) {
                // .
                FilterLevel revel = matchExcludeFilter(jsLintError.getReason());
                if (i < maxerr && !FilterLevel.IGNORE.equals(revel)) {
                    JsMarkingSupport support = new JsMarkingSupport(
                            iFile.createMarker(JSLintPluginConstant.JS_TYPE_MARKER));
                    support.putMessageAttribute(jsLintError.getReason());
                    if (FilterLevel.ERROR.equals(revel)) {
                        support.putSeverityAttribute(IMarker.SEVERITY_ERROR);
                    } else {
                        support.putSeverityAttribute(IMarker.SEVERITY_WARNING);
                    }
                    support.putLocationAttribute(
                            Messages.VM0000.format(jsLintError.getLine().intValue() - startPosition));
                    support.putLineNumAttribute(jsLintError.getLine().intValue() - startPosition);
                    list.add(support);
                    i++;
                }
            }
        }
    }

    /**
     * ???????.
     * 
     * @param list ?.
     */
    private void mark(List<JsMarkingSupport> list) {
        int i = 0;
        int atFile = list.size() / 400;
        if (atFile == 0) {
            atFile = 1;
        }

        for (JsMarkingSupport jsMarkingSupport : list) {
            jsMarkingSupport.marking();
            i++;
            if (i % atFile == 0) {
                monitor.subTask(Messages.T0008.format(i + 1, list.size()));
                this.monitor.worked(TASK_MARK_VIEW * atFile / list.size());
            }
        }
    }

    /**
     * ???????????.
     * 
     * @param reason ?.
     * @return ?????,????null.
     */
    private FilterLevel matchExcludeFilter(String reason) {

        FilterBean[] filterBeans = bean.getFilterBeans();
        FilterLevel revel = null;
        for (FilterBean filterBean : filterBeans) {
            if (!filterBean.isState()) {
                continue;
            }
            Pattern pattern = Pattern.compile(filterBean.getRegex());
            Matcher matcher = pattern.matcher(reason);
            // ??????
            if (matcher.matches()) {
                revel = filterBean.getRevel();
                if (FilterLevel.IGNORE.equals(revel)) {
                    // ?????.
                    return revel;
                }
            }

        }
        return revel;
    }

    /**
     * ??(???)??.
     * 
     * @return ??(???)
     */
    protected IResource getResource() {

        return resource;
    }

    @Override
    public void cansel() {

        monitor.setCanceled(true);
    }

    /**
     * ??.
     * 
     * @return .
     */
    protected ConfigBean getBean() {
        return bean;
    }
}