So as in the Java plugin, I do not have to do anything :) Every time JavaScriptSquidSensor finds JavaScript code my rules will run.
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<sonar.apiVersion>5.6.1</sonar.apiVersion>
- <javascript.plugin.version>2.14</javascript.plugin.version>
+ <javascript.plugin.version>2.15</javascript.plugin.version>
<jdk.min.version>1.8</jdk.min.version>
- <sonar.pluginKey>helloworld</sonar.pluginKey>
+ <sonar.pluginKey>customjavascriptplugin</sonar.pluginKey>
</properties>
<dependencies>
<version>${sonar.apiVersion}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.sonarsource.java</groupId>
+ <artifactId>javascript-checks-testkit</artifactId>
+ <version>${javascript.plugin.version}</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
public void define(Context context) {
ImmutableList.Builder<Object> builder = ImmutableList.builder();
builder.add(
- );
+ CustomRulesDefinition.class);
context.addExtensions(builder.build());
}
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;
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<Class> checks = CheckList.getChecks();
new RulesDefinitionAnnotationLoader().load(repository, Iterables.toArray(checks, Class.class));
for (Class ruleClass : checks) {
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);
}
}
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());
}
}
- 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) {
+++ /dev/null
-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<Tree> 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<TreeVisitor> treeVisitors, Iterable<InputFile> 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<TreeVisitor> 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<TreeVisitor> visitors, ScriptTree scriptTree) {
- JavaScriptVisitorContext context = new JavaScriptVisitorContext(scriptTree, inputFile.file(), settings);
-
- highlightSymbols(sensorContext.newSymbolTable().onFile(inputFile), context);
-
- List<Issue> 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<Issue> 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<TreeVisitor> 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
+++ /dev/null
-/*
- * 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<Checks<JavaScriptCheck>> 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<Class> checkClass) {
- checksByRepository.add(checkFactory
- .<JavaScriptCheck>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<JavaScriptCheck> all() {
- List<JavaScriptCheck> allVisitors = Lists.newArrayList();
-
- for (Checks<JavaScriptCheck> checks : checksByRepository) {
- allVisitors.addAll(checks.all());
- }
-
- return allVisitors;
- }
-
- public List<SeCheck> seChecks() {
- List<SeCheck> checks = new ArrayList<>();
- for (JavaScriptCheck check : all()) {
- if (check instanceof SeCheck) {
- checks.add((SeCheck) check);
- }
- }
-
- return checks;
- }
-
- public List<TreeVisitor> visitorChecks() {
- List<TreeVisitor> 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<JavaScriptCheck> checks : checksByRepository) {
- ruleKey = checks.ruleKey(check);
-
- if (ruleKey != null) {
- return ruleKey;
- }
- }
- return null;
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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 <code>"/*"</code>) or a C++-like comment
- * (i.e., it starts with <code>"//"</code>).
- */
-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
+++ /dev/null
-/*
- * 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.
- * <p>
- * 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