Package com.googlecode.jslint4java.cli

Source Code of com.googlecode.jslint4java.cli.Main

package com.googlecode.jslint4java.cli;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterDescription;
import com.beust.jcommander.ParameterException;
import com.beust.jcommander.Parameterized;
import com.googlecode.jslint4java.Issue;
import com.googlecode.jslint4java.JSLint;
import com.googlecode.jslint4java.JSLintBuilder;
import com.googlecode.jslint4java.JSLintResult;
import com.googlecode.jslint4java.Option;
import com.googlecode.jslint4java.UnicodeBomInputStream;
import com.googlecode.jslint4java.formatter.CheckstyleXmlFormatter;
import com.googlecode.jslint4java.formatter.JSLintResultFormatter;
import com.googlecode.jslint4java.formatter.JSLintXmlFormatter;
import com.googlecode.jslint4java.formatter.JUnitXmlFormatter;
import com.googlecode.jslint4java.formatter.PlainFormatter;
import com.googlecode.jslint4java.formatter.ReportFormatter;

/**
* A command line interface to {@link JSLint}.
*
* @author dom
*/
class Main {

    private static final class ParameterDescriptionComparator implements
            Comparator<ParameterDescription> {
        public int compare(ParameterDescription a, ParameterDescription b) {
            return a.getLongestName().compareTo(b.getLongestName());
        }
    }

    /**
     * The default command line output.
     */
    private static final class DefaultFormatter implements JSLintResultFormatter {
        public String format(JSLintResult result) {
            if (result.getIssues().isEmpty()) {
                return "";
            }
            String nl = System.getProperty("line.separator");
            StringBuilder sb = new StringBuilder();
            for (Issue issue : result.getIssues()) {
                sb.append(PROGNAME);
                sb.append(':');
                sb.append(issue.toString());
                sb.append(nl);
            }
            // Strip trailing newline if present.  The interface is wrong; we should return
            // a list of lines, not a String.
            sb.delete(sb.length() - nl.length(), sb.length());
            return sb.toString();
        }

        public String footer() {
            return null;
        }

        public String header() {
            return null;
        }
    }

    /**
     * This is just to avoid calling {@link System#exit(int)} outside of main()…
     */
    // @VisibleForTesting
    @SuppressWarnings("serial")
    public static class DieException extends RuntimeException {
        private final int code;

        public DieException(String message, int code) {
            super(message);
            this.code = code;
        }

        public int getCode() {
            return code;
        }
    }

    private static final String FULL_PROGRAM_NAME = "jslint4java";

    private static final String PROGNAME = "jslint";

    /**
     * The main entry point. Try passing in "--help" for more details.
     *
     * @param args
     *            One or more JavaScript files.
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        try {
            System.exit(new Main().run(args));
        } catch (DieException e) {
            if (e.getMessage() != null) {
                System.err.println(PROGNAME + ": " + e.getMessage());
            }
            System.exit(e.getCode());
        }
    }

    // @VisibleForTesting.
    int run(String[] args) throws IOException {
        List<String> files = processOptions(args);
        if (formatter.header() != null) {
            info(formatter.header());
        }
        for (String file : files) {
            lintFile(file);
        }
        if (formatter.footer() != null) {
            info(formatter.footer());
        }
        return isErrored() ? 1 : 0;
    }

    private Charset encoding = Charset.defaultCharset();

    private boolean errored = false;

    private JSLintResultFormatter formatter;

    private JSLint lint;

    private final JSLintBuilder lintBuilder = new JSLintBuilder();

    private void die(String message) {
        throw new DieException(message, 1);
    }

    /**
     * Fetch the named {@link Option}, or null if there is no matching one.
     */
    private Option getOption(String optName) {
        try {
            return Option.valueOf(optName);
        } catch (IllegalArgumentException e) {
            return null;
        }
    }

    private void info(String message) {
        System.out.println(message);
    }

    private boolean isErrored() {
        return errored;
    }

    // Eclipse's static analysis thinks I never close the UnicodeBomInputStream below.
    private void lintFile(String file) throws IOException {
        BufferedReader reader = null;
        try {
            reader = readerForFile(file);
            JSLintResult result = lint.lint(file, reader);
            String msg = formatter.format(result);
            if (msg.length() > 0) {
                info(msg);
            }
            if (!result.getIssues().isEmpty()) {
                setErrored(true);
            }
        } catch (FileNotFoundException e) {
            die(file + ": No such file or directory.");
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
    }

    /**
     * Return a {@link BufferedReader} for {@code file}. If {@code file} is "-" then stdin will be
     * used instead.
     */
    @SuppressWarnings("resource")
    private BufferedReader readerForFile(String file) throws IOException, FileNotFoundException {
        InputStream inputStream = "-".equals(file) ? System.in : new FileInputStream(file);
        return new BufferedReader(new InputStreamReader(
                new UnicodeBomInputStream(inputStream).skipBOM(), encoding));
    }

    private JSLint makeLint(Flags flags) {
        try {
            if (flags.timeout > 0) {
                lintBuilder.timeout(flags.timeout);
            }
            if (flags.jslint != null) {
                return lintBuilder.fromFile(new File(flags.jslint));
            } else {
                return lintBuilder.fromDefault();
            }
        } catch (IOException e) {
            die(e.getMessage());
        }
        return null;
    }

    private List<String> processOptions(String[] args) {
        JSLintFlags jslintFlags = new JSLintFlags();
        Flags flags = new Flags();
        JCommander jc = new JCommander(new Object[] { flags , jslintFlags });
        jc.setProgramName(FULL_PROGRAM_NAME);
        try {
            jc.parse(args);
        } catch (ParameterException e) {
            info(e.getMessage());
            usage(jc);
        }
        if (flags.version) {
            version();
        }
        if (flags.help) {
            usage(jc);
        }
        if (flags.encoding != null) {
            encoding = flags.encoding;
        }
        lint = makeLint(flags);
        setResultFormatter(flags.report);
        for (ParameterDescription pd : jc.getParameters()) {
            Parameterized p = pd.getParameterized();
            // Is it declared on JSLintFlags?
            if (!pd.getObject().getClass().isAssignableFrom(JSLintFlags.class)) {
                continue;
            }
            try {
                // Need to get Option.
                Option o = getOption(p.getName());
                // Need to get value.
                Object val = p.get(jslintFlags);
                if (val == null) {
                    continue;
                }
                Class<?> type = p.getType();
                if (type.isAssignableFrom(Boolean.class)) {
                    lint.addOption(o);
                }
                // In theory, everything else should be a String for later parsing.
                else if (type.isAssignableFrom(String.class)) {
                    lint.addOption(o, (String) val);
                } else {
                    die("unknown type \"" + type + "\" (for " + p.getName() + ")");
                }
            } catch (IllegalArgumentException e) {
                die(e.getMessage());
            }
        }
        if (flags.files.isEmpty()) {
            usage(jc);
            return null; // can never happen
        } else {
            return flags.files;
        }
    }

    private void setErrored(boolean errored) {
        this.errored = errored;
    }

    private void setResultFormatter(String reportType) {
        if (reportType == null || reportType.equals("")) {
            // The original CLI behaviour: one-per-line, with prefix.
            formatter = new DefaultFormatter();
        } else if (reportType.equals("plain")) {
            formatter = new PlainFormatter();
        } else if (reportType.equals("xml")) {
            formatter = new JSLintXmlFormatter();
        } else if (reportType.equals("junit")) {
            formatter = new JUnitXmlFormatter();
        } else if (reportType.equals("report")) {
            formatter = new ReportFormatter();
        } else if (reportType.equals("checkstyle")) {
            formatter = new CheckstyleXmlFormatter();
        } else {
            die("unknown report type '" + reportType + "'");
        }

    }

    private void usage(JCommander jc) {
        info(String.format("Usage: %s [options] file.js ...", FULL_PROGRAM_NAME));
        info("");
        List<ParameterDescription> parameters = jc.getParameters();
        String spec = " %-" + getLongestName(parameters) + "s %s";
        Collections.sort(parameters, new ParameterDescriptionComparator());
        for (ParameterDescription pd : parameters) {
            info(String.format(spec, pd.getLongestName(), pd.getDescription()));
        }
        info("");
        version();
    }

    /** Return the length of the longest parameter name. */
    private int getLongestName(List<ParameterDescription> parameters) {
        int length = 0;
        for (ParameterDescription pd : parameters) {
            if (pd.getLongestName().length() > length) {
                length = pd.getLongestName().length();
            }
        }
        return length;
    }

    private void version() {
        // TODO: display jslint4java version as well.
        if (lint == null) {
            lint = lintBuilder.fromDefault();
        }
        info("using jslint version " + lint.getEdition());
        throw new DieException(null, 0);
    }

}
TOP

Related Classes of com.googlecode.jslint4java.cli.Main

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.