From de41464e10650de7580530a18fcbab39817f3f3c Mon Sep 17 00:00:00 2001 From: Gustavo Martin Morcuende Date: Sun, 21 Aug 2016 06:17:50 +0200 Subject: [PATCH] sonar JavaScript plugin: any class extending CustomJavaScriptRulesDefinition will be injected and used in JavaScriptSquidSensor. So as in the Java plugin, I do not have to do anything :) Every time JavaScriptSquidSensor finds JavaScript code my rules will run. --- .../Plugins/sonar-custom-javascript-plugin/pom.xml | 10 +- .../plugins/custom/javascript/CustomPlugin.java | 2 +- .../custom/javascript/CustomRulesDefinition.java | 55 +++- .../plugins/custom/javascript/CustomSensor.java | 319 --------------------- .../custom/javascript/JavaScriptChecks.java | 117 -------- .../minify/AverageLineLengthCalculator.java | 126 -------- .../javascript/minify/MinificationAssessor.java | 74 ----- 7 files changed, 50 insertions(+), 653 deletions(-) delete mode 100644 Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/CustomSensor.java delete mode 100644 Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/JavaScriptChecks.java delete mode 100644 Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/minify/AverageLineLengthCalculator.java delete mode 100644 Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/minify/MinificationAssessor.java diff --git a/Sonar/Plugins/sonar-custom-javascript-plugin/pom.xml b/Sonar/Plugins/sonar-custom-javascript-plugin/pom.xml index 3995d92..2b85884 100644 --- a/Sonar/Plugins/sonar-custom-javascript-plugin/pom.xml +++ b/Sonar/Plugins/sonar-custom-javascript-plugin/pom.xml @@ -17,9 +17,9 @@ UTF-8 5.6.1 - 2.14 + 2.15 1.8 - helloworld + customjavascriptplugin @@ -58,6 +58,12 @@ ${sonar.apiVersion} test + + org.sonarsource.java + javascript-checks-testkit + ${javascript.plugin.version} + test + org.easytesting fest-assert diff --git a/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/CustomPlugin.java b/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/CustomPlugin.java index 641afa8..ef7f0d9 100644 --- a/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/CustomPlugin.java +++ b/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/CustomPlugin.java @@ -10,7 +10,7 @@ public class CustomPlugin implements Plugin { public void define(Context context) { ImmutableList.Builder builder = ImmutableList.builder(); builder.add( - ); + CustomRulesDefinition.class); context.addExtensions(builder.build()); } diff --git a/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/CustomRulesDefinition.java b/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/CustomRulesDefinition.java index 4180004..5d98de2 100644 --- a/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/CustomRulesDefinition.java +++ b/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/CustomRulesDefinition.java @@ -9,13 +9,11 @@ import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; import org.sonar.api.rule.RuleStatus; import org.sonar.api.server.debt.DebtRemediationFunction; -import org.sonar.api.server.rule.RulesDefinition; import org.sonar.api.server.rule.RulesDefinitionAnnotationLoader; import org.sonar.api.utils.AnnotationUtils; -import org.sonar.check.Cardinality; import org.sonar.plugins.javascript.JavaScriptLanguage; +import org.sonar.plugins.javascript.api.CustomJavaScriptRulesDefinition; import org.sonar.squidbridge.annotations.RuleTemplate; -import org.sonar.squidbridge.rules.ExternalDescriptionLoader; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; @@ -25,16 +23,46 @@ import com.google.gson.Gson; import de.example.custom.javascript.checks.CheckList; -public class CustomRulesDefinition implements RulesDefinition { + +/** + * This class will be injected (SonarQube is using PicoContainer) in + * org.sonar.plugins.javascript.JavaScriptSquidSensor. + * + * It seems like the SonarQube developers in charge of writing the JavaScript plugin tried to + * make easy the creation of custom Java plugins. + * + * So, JavaScriptSquidSensor will be the object that will run my rules (my Checks) whenever it finds JavaScript code. + * I do not have to do anything else, what is great! + * + */ +public class CustomRulesDefinition extends CustomJavaScriptRulesDefinition { private static final String RESOURCE_BASE_PATH = "/de/example/l10n/javascript/rules/custom"; private final Gson gson = new Gson(); + @Override + public String repositoryName() { + return CheckList.REPOSITORY_NAME; + } + + @Override + public String repositoryKey() { + return CheckList.REPOSITORY_KEY; + } + + @Override + public Class[] checkClasses() { + return CheckList.getChecks().toArray(); + } + + /** + * I do not want to use the define method implemented in org.sonar.plugins.javascript.api.CustomJavaScriptRulesDefinition. + */ @Override public void define(Context context) { NewRepository repository = context - .createRepository(CheckList.REPOSITORY_KEY, JavaScriptLanguage.KEY) - .setName(CheckList.REPOSITORY_NAME); + .createRepository(repositoryKey(), JavaScriptLanguage.KEY) + .setName(repositoryName()); List checks = CheckList.getChecks(); new RulesDefinitionAnnotationLoader().load(repository, Iterables.toArray(checks, Class.class)); for (Class ruleClass : checks) { @@ -51,17 +79,16 @@ public class CustomRulesDefinition implements RulesDefinition { throw new IllegalArgumentException("No Rule annotation was found on " + ruleClass); } String ruleKey = ruleAnnotation.key(); - if (StringUtils.isEmpty(ruleKey)) { + if (StringUtils.isEmpty(ruleKey)) { throw new IllegalArgumentException("No key is defined in Rule annotation of " + ruleClass); } NewRule rule = repository.rule(ruleKey); if (rule == null) { throw new IllegalStateException("No rule was created for " + ruleClass + " in " + repository.key()); } + + // Check whether it is a Rule Template. rule.setTemplate(AnnotationUtils.getAnnotation(ruleClass, RuleTemplate.class) != null); - if (ruleAnnotation.cardinality() == Cardinality.MULTIPLE) { - throw new IllegalArgumentException("Cardinality is not supported, use the RuleTemplate annotation instead for " + ruleClass); - } ruleMetadata(ruleClass, rule); } @@ -73,7 +100,7 @@ public class CustomRulesDefinition implements RulesDefinition { } private void addMetadata(NewRule rule, String metadataKey) { - URL resource = ExternalDescriptionLoader.class.getResource(RESOURCE_BASE_PATH + "/" + metadataKey + "_java.json"); + URL resource = CustomRulesDefinition.class.getResource(RESOURCE_BASE_PATH + "/" + metadataKey + "_javascript.json"); if (resource != null) { RuleMetatada metatada = gson.fromJson(readResource(resource), RuleMetatada.class); rule.setSeverity(metatada.defaultSeverity.toUpperCase()); @@ -87,14 +114,14 @@ public class CustomRulesDefinition implements RulesDefinition { } } - private static void addHtmlDescription(NewRule rule, String metadataKey) { - URL resource = CustomRulesDefinition.class.getResource(RESOURCE_BASE_PATH + "/" + metadataKey + "_java.html"); + private void addHtmlDescription(NewRule rule, String metadataKey) { + URL resource = CustomRulesDefinition.class.getResource(RESOURCE_BASE_PATH + "/" + metadataKey + "_javascript.html"); if (resource != null) { rule.setHtmlDescription(readResource(resource)); } } - private static String readResource(URL resource) { + private String readResource(URL resource) { try { return Resources.toString(resource, Charsets.UTF_8); } catch (IOException e) { diff --git a/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/CustomSensor.java b/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/CustomSensor.java deleted file mode 100644 index e5285a5..0000000 --- a/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/CustomSensor.java +++ /dev/null @@ -1,319 +0,0 @@ -package de.example.plugins.custom.javascript; -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import java.io.File; -import java.io.InterruptedIOException; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nullable; - -import org.sonar.api.batch.fs.FilePredicate; -import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.fs.InputFile.Type; -import org.sonar.api.batch.fs.TextRange; -import org.sonar.api.batch.rule.CheckFactory; -import org.sonar.api.batch.sensor.Sensor; -import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.batch.sensor.SensorDescriptor; -import org.sonar.api.batch.sensor.issue.NewIssue; -import org.sonar.api.batch.sensor.issue.NewIssueLocation; -import org.sonar.api.batch.sensor.symbol.NewSymbolTable; -import org.sonar.api.config.Settings; -import org.sonar.api.issue.NoSonarFilter; -import org.sonar.api.measures.FileLinesContextFactory; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.javascript.checks.ParsingErrorCheck; -import org.sonar.javascript.highlighter.HighlightSymbolTableBuilder; -import org.sonar.javascript.parser.JavaScriptParserBuilder; -import org.sonar.javascript.tree.visitors.CharsetAwareVisitor; -import org.sonar.javascript.visitors.JavaScriptVisitorContext; -import org.sonar.plugins.javascript.JavaScriptLanguage; -import org.sonar.plugins.javascript.api.CustomJavaScriptRulesDefinition; -import org.sonar.plugins.javascript.api.JavaScriptCheck; -import org.sonar.plugins.javascript.api.tree.ScriptTree; -import org.sonar.plugins.javascript.api.tree.Tree; -import org.sonar.plugins.javascript.api.visitors.FileIssue; -import org.sonar.plugins.javascript.api.visitors.Issue; -import org.sonar.plugins.javascript.api.visitors.IssueLocation; -import org.sonar.plugins.javascript.api.visitors.LineIssue; -import org.sonar.plugins.javascript.api.visitors.PreciseIssue; -import org.sonar.plugins.javascript.api.visitors.TreeVisitor; -import org.sonar.plugins.javascript.api.visitors.TreeVisitorContext; -import org.sonar.squidbridge.api.AnalysisException; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; -import com.google.common.base.Throwables; -import com.google.common.collect.Lists; -import com.sonar.sslr.api.RecognitionException; -import com.sonar.sslr.api.typed.ActionParser; - -import de.example.custom.javascript.checks.CheckList; -import de.example.plugins.custom.javascript.minify.MinificationAssessor; - -public class CustomSensor implements Sensor { - - private static final Logger LOG = Loggers.get(CustomSensor.class); - - private final JavaScriptChecks checks; - private final FileSystem fileSystem; - private final FilePredicate mainFilePredicate; - private final Settings settings; - private final ActionParser parser; - // parsingErrorRuleKey equals null if ParsingErrorCheck is not activated - private RuleKey parsingErrorRuleKey = null; - - public CustomSensor( - CheckFactory checkFactory, FileLinesContextFactory fileLinesContextFactory, FileSystem fileSystem, NoSonarFilter noSonarFilter, Settings settings) { - this(checkFactory, fileSystem, settings, null); - } - - public CustomSensor( - CheckFactory checkFactory, FileSystem fileSystem, - Settings settings, @Nullable CustomJavaScriptRulesDefinition[] customRulesDefinition - ) { - - this.checks = JavaScriptChecks.createJavaScriptCheck(checkFactory) - .addChecks(CheckList.REPOSITORY_KEY, CheckList.getChecks()) - .addCustomChecks(customRulesDefinition); - this.fileSystem = fileSystem; - this.mainFilePredicate = fileSystem.predicates().and( - fileSystem.predicates().hasType(InputFile.Type.MAIN), - fileSystem.predicates().hasLanguage(JavaScriptLanguage.KEY)); - this.settings = settings; - this.parser = JavaScriptParserBuilder.createParser(getEncoding()); - } - - @VisibleForTesting - protected void analyseFiles(SensorContext context, List treeVisitors, Iterable inputFiles) { - for (InputFile inputFile : inputFiles) { - if (!isExcluded(inputFile.file())) { - analyse(context, inputFile, treeVisitors); - } - } - } - - private Charset getEncoding() { - return fileSystem.encoding(); - } - - - private void analyse(SensorContext sensorContext, InputFile inputFile, List visitors) { - ScriptTree scriptTree; - - try { - scriptTree = (ScriptTree) parser.parse(new java.io.File(inputFile.absolutePath())); - scanFile(sensorContext, inputFile, visitors, scriptTree); - - } catch (RecognitionException e) { - checkInterrupted(e); - LOG.error("Unable to parse file: " + inputFile.absolutePath()); - LOG.error(e.getMessage()); - processRecognitionException(e, sensorContext, inputFile); - - } catch (Exception e) { - checkInterrupted(e); - throw new AnalysisException("Unable to analyse file: " + inputFile.absolutePath(), e); - } - - } - - private static void checkInterrupted(Exception e) { - Throwable cause = Throwables.getRootCause(e); - if (cause instanceof InterruptedException || cause instanceof InterruptedIOException) { - throw new AnalysisException("Analysis cancelled", e); - } - } - - private void processRecognitionException(RecognitionException e, SensorContext sensorContext, InputFile inputFile) { - if (parsingErrorRuleKey != null) { - NewIssue newIssue = sensorContext.newIssue(); - - NewIssueLocation primaryLocation = newIssue.newLocation() - .message(e.getMessage()) - .on(inputFile) - .at(inputFile.selectLine(e.getLine())); - - newIssue - .forRule(parsingErrorRuleKey) - .at(primaryLocation) - .save(); - } - } - - private void scanFile(SensorContext sensorContext, InputFile inputFile, List visitors, ScriptTree scriptTree) { - JavaScriptVisitorContext context = new JavaScriptVisitorContext(scriptTree, inputFile.file(), settings); - - highlightSymbols(sensorContext.newSymbolTable().onFile(inputFile), context); - - List fileIssues = new ArrayList<>(); - - for (TreeVisitor visitor : visitors) { - if (visitor instanceof CharsetAwareVisitor) { - ((CharsetAwareVisitor) visitor).setCharset(fileSystem.encoding()); - } - - if (visitor instanceof JavaScriptCheck) { - fileIssues.addAll(((JavaScriptCheck) visitor).scanFile(context)); - - } else { - visitor.scanTree(context); - } - - } - - saveFileIssues(sensorContext, fileIssues, inputFile); - } - - - private static void highlightSymbols(NewSymbolTable newSymbolTable, TreeVisitorContext context) { - HighlightSymbolTableBuilder.build(newSymbolTable, context); - } - - private void saveFileIssues(SensorContext sensorContext, List fileIssues, InputFile inputFile) { - for (Issue issue : fileIssues) { - RuleKey ruleKey = ruleKey(issue.check()); - if (issue instanceof FileIssue) { - saveFileIssue(sensorContext, inputFile, ruleKey, (FileIssue) issue); - - } else if (issue instanceof LineIssue) { - saveLineIssue(sensorContext, inputFile, ruleKey, (LineIssue) issue); - - } else { - savePreciseIssue(sensorContext, inputFile, ruleKey, (PreciseIssue)issue); - } - } - } - - private static void savePreciseIssue(SensorContext sensorContext, InputFile inputFile, RuleKey ruleKey, PreciseIssue issue) { - NewIssue newIssue = sensorContext.newIssue(); - - newIssue - .forRule(ruleKey) - .at(newLocation(inputFile, newIssue, issue.primaryLocation())); - - if (issue.cost() != null) { - newIssue.gap(issue.cost()); - } - - for (IssueLocation secondary : issue.secondaryLocations()) { - newIssue.addLocation(newLocation(inputFile, newIssue, secondary)); - } - newIssue.save(); - } - - - private static NewIssueLocation newLocation(InputFile inputFile, NewIssue issue, IssueLocation location) { - TextRange range = inputFile.newRange( - location.startLine(), location.startLineOffset(), location.endLine(), location.endLineOffset()); - - NewIssueLocation newLocation = issue.newLocation() - .on(inputFile) - .at(range); - - if (location.message() != null) { - newLocation.message(location.message()); - } - return newLocation; - } - - - private RuleKey ruleKey(JavaScriptCheck check) { - Preconditions.checkNotNull(check); - RuleKey ruleKey = checks.ruleKeyFor(check); - if (ruleKey == null) { - throw new IllegalStateException("No rule key found for a rule"); - } - return ruleKey; - } - - public boolean isExcluded(File file) { - boolean isMinified = new MinificationAssessor(getEncoding()).isMinified(file); - if (isMinified) { - LOG.debug("File [" + file.getAbsolutePath() + "] looks like a minified file and will not be analyzed"); - } - return isMinified; - } - - @Override - public void describe(SensorDescriptor descriptor) { - descriptor - .onlyOnLanguage(JavaScriptLanguage.KEY) - .name("Custom JavaScript Sensor") - .onlyOnFileType(Type.MAIN); - } - - @Override - public void execute(SensorContext context) { - List treeVisitors = Lists.newArrayList(); - treeVisitors.addAll(checks.visitorChecks()); - - for (TreeVisitor check : treeVisitors) { - if (check instanceof ParsingErrorCheck) { - parsingErrorRuleKey = checks.ruleKeyFor((JavaScriptCheck) check); - break; - } - } - - analyseFiles(context, treeVisitors, fileSystem.inputFiles(mainFilePredicate)); - - } - - - private static void saveLineIssue(SensorContext sensorContext, InputFile inputFile, RuleKey ruleKey, LineIssue issue) { - NewIssue newIssue = sensorContext.newIssue(); - - NewIssueLocation primaryLocation = newIssue.newLocation() - .message(issue.message()) - .on(inputFile) - .at(inputFile.selectLine(issue.line())); - - saveIssue(newIssue, primaryLocation, ruleKey, issue); - } - - private static void saveFileIssue(SensorContext sensorContext, InputFile inputFile, RuleKey ruleKey, FileIssue issue) { - NewIssue newIssue = sensorContext.newIssue(); - - NewIssueLocation primaryLocation = newIssue.newLocation() - .message(issue.message()) - .on(inputFile); - - saveIssue(newIssue, primaryLocation, ruleKey, issue); - } - - private static void saveIssue(NewIssue newIssue, NewIssueLocation primaryLocation, RuleKey ruleKey, Issue issue) { - newIssue - .forRule(ruleKey) - .at(primaryLocation); - - if (issue.cost() != null) { - newIssue.gap(issue.cost()); - } - - newIssue.save(); - } - -} \ No newline at end of file diff --git a/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/JavaScriptChecks.java b/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/JavaScriptChecks.java deleted file mode 100644 index c6af4e7..0000000 --- a/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/JavaScriptChecks.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package de.example.plugins.custom.javascript; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import javax.annotation.Nullable; -import org.sonar.api.batch.rule.CheckFactory; -import org.sonar.api.batch.rule.Checks; -import org.sonar.api.rule.RuleKey; -import org.sonar.javascript.se.SeCheck; -import org.sonar.plugins.javascript.api.CustomJavaScriptRulesDefinition; -import org.sonar.plugins.javascript.api.JavaScriptCheck; -import org.sonar.plugins.javascript.api.visitors.TreeVisitor; - -/** - * Wrapper around Checks Object to ease the manipulation of the different JavaScript rule repositories. - */ -public class JavaScriptChecks { - - private final CheckFactory checkFactory; - private Set> checksByRepository = Sets.newHashSet(); - - private JavaScriptChecks(CheckFactory checkFactory) { - this.checkFactory = checkFactory; - } - - public static JavaScriptChecks createJavaScriptCheck(CheckFactory checkFactory) { - return new JavaScriptChecks(checkFactory); - } - - public JavaScriptChecks addChecks(String repositoryKey, Iterable checkClass) { - checksByRepository.add(checkFactory - .create(repositoryKey) - .addAnnotatedChecks(checkClass)); - - return this; - } - - public JavaScriptChecks addCustomChecks(@Nullable CustomJavaScriptRulesDefinition[] customRulesDefinitions) { - if (customRulesDefinitions != null) { - - for (CustomJavaScriptRulesDefinition rulesDefinition : customRulesDefinitions) { - addChecks(rulesDefinition.repositoryKey(), Lists.newArrayList(rulesDefinition.checkClasses())); - } - } - - return this; - } - - private List all() { - List allVisitors = Lists.newArrayList(); - - for (Checks checks : checksByRepository) { - allVisitors.addAll(checks.all()); - } - - return allVisitors; - } - - public List seChecks() { - List checks = new ArrayList<>(); - for (JavaScriptCheck check : all()) { - if (check instanceof SeCheck) { - checks.add((SeCheck) check); - } - } - - return checks; - } - - public List visitorChecks() { - List checks = new ArrayList<>(); - for (JavaScriptCheck check : all()) { - if (check instanceof TreeVisitor) { - checks.add((TreeVisitor) check); - } - } - - return checks; - } - - @Nullable - public RuleKey ruleKeyFor(JavaScriptCheck check) { - RuleKey ruleKey; - - for (Checks checks : checksByRepository) { - ruleKey = checks.ruleKey(check); - - if (ruleKey != null) { - return ruleKey; - } - } - return null; - } - -} \ No newline at end of file diff --git a/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/minify/AverageLineLengthCalculator.java b/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/minify/AverageLineLengthCalculator.java deleted file mode 100644 index 8cdc3b2..0000000 --- a/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/minify/AverageLineLengthCalculator.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package de.example.plugins.custom.javascript.minify; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.Charset; -import org.sonar.squidbridge.api.AnalysisException; - -/** - * An instance of this class computes the average line length of file. - * Before making the computation, it discards all lines which are part - * of the header comment. - * The header comment is a comment which starts on the first line of the file. - * It may be either a C-like comment (i.e., it starts with "/*") or a C++-like comment - * (i.e., it starts with "//"). - */ -class AverageLineLengthCalculator { - - private File file; - - private boolean isAtFirstLine = true; - - private boolean isInHeaderComment = false; - - private boolean isClike = false; - - private Charset encoding; - - public AverageLineLengthCalculator(File file, Charset encoding) { - this.file = file; - this.encoding = encoding; - } - - public int getAverageLineLength() { - long nbLines = 0; - long nbCharacters = 0; - - try (BufferedReader reader = getReader(file)) { - String line; - while ((line = reader.readLine()) != null) { - if (!isLineInHeaderComment(line)) { - nbLines++; - nbCharacters += line.length(); - } - } - } catch (IOException e) { - handleException(e, file); - } - - return nbLines > 0 ? (int) (nbCharacters / nbLines) : 0; - } - - public boolean isLineInHeaderComment(String line) { - String trimmedLine = line.trim(); - if (isAtFirstLine) { - isAtFirstLine = false; - return isFirstLineInHeaderComment(trimmedLine); - } else if (isInHeaderComment) { - return isSubsequentLineInHeaderComment(trimmedLine); - } - return false; - } - - private boolean isFirstLineInHeaderComment(String line) { - if (line.startsWith("/*")) { - isClike = true; - isInHeaderComment = !line.endsWith("*/"); - return true; - } else if (line.startsWith("//")) { - isClike = false; - isInHeaderComment = true; - return true; - } - return false; - } - - private boolean isSubsequentLineInHeaderComment(String line) { - if (isClike) { - if (line.endsWith("*/")) { - isInHeaderComment = false; - } else if (line.contains("*/")) { - // case of */ followed with something, possibly a long minified line - isInHeaderComment = false; - return false; - } - return true; - } else { - if (line.startsWith("//")) { - return true; - } else { - isInHeaderComment = false; - return false; - } - } - } - - private BufferedReader getReader(File file) throws IOException { - return new BufferedReader(new InputStreamReader(new FileInputStream(file), encoding)); - } - - private static void handleException(IOException e, File file) { - throw new AnalysisException("Unable to analyse file: " + file.getAbsolutePath(), e); - } - -} \ No newline at end of file diff --git a/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/minify/MinificationAssessor.java b/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/minify/MinificationAssessor.java deleted file mode 100644 index c0cbffa..0000000 --- a/Sonar/Plugins/sonar-custom-javascript-plugin/src/main/java/de/example/plugins/custom/javascript/minify/MinificationAssessor.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SonarQube JavaScript Plugin - * Copyright (C) 2011-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package de.example.plugins.custom.javascript.minify; - -import java.io.File; -import java.nio.charset.Charset; - -/** - * An object to assess if a .js file is a minified file or not. - *

- * An instance of this class is likely to consider as minified a .js file that, - * although formally not minified, has an unusually high average line length. - * This situation is typical of files that have been generated by some tool. - * Such files are of poor interest as regards a SonarQube analysis. - */ -public class MinificationAssessor { - - private static final int DEFAULT_AVERAGE_LINE_LENGTH_THRESHOLD = 200; - - private Charset encoding; - - /** - * Value of the average line length - * (= number of chars in the file / number of lines in the file) - * below which a file is not assessed as being a minified file. - */ - private int averageLineLengthThreshold; - - public MinificationAssessor(Charset encoding) { - this(encoding, DEFAULT_AVERAGE_LINE_LENGTH_THRESHOLD); - } - - public MinificationAssessor(Charset encoding, int averageLineLengthThreshold) { - this.encoding = encoding; - this.averageLineLengthThreshold = averageLineLengthThreshold; - } - - public boolean isMinified(File file) { - return isJavaScriptFile(file) && - (hasMinifiedFileName(file) || hasExcessiveAverageLineLength(file)); - } - - private static boolean hasMinifiedFileName(File file) { - String fileName = file.getName(); - return fileName.endsWith("-min.js") || fileName.endsWith(".min.js"); - } - - private static boolean isJavaScriptFile(File file) { - return file.getName().endsWith(".js"); - } - - private boolean hasExcessiveAverageLineLength(File file) { - int averageLineLength = new AverageLineLengthCalculator(file, encoding).getAverageLineLength(); - return averageLineLength > averageLineLengthThreshold; - } - -} \ No newline at end of file -- 2.1.4